]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
support reading TeX's $$...$$ syntax
[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(MathStyles 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(std::ostream & os, bool fragile) const
268 {
269         for (row_type row = 0; row < nrows(); ++row) {
270                 for (col_type col = 0; col < ncols(); ++col) {
271                         cell(index(row, col)).write(os, fragile);
272                         os << eocString(col);
273                 }
274                 os << eolString(row);
275         }
276 }
277
278
279 string MathGridInset::eolString(row_type row) const
280 {
281         if (row + 1 == nrows()) 
282                 return "";
283
284         if (rowinfo_[row].skip_.value() != 0)
285                 return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n";
286
287         // make sure an upcoming '[' does not break anything
288         MathArray const & c = cell(index(row + 1, 0));
289         if (c.size() && (*c.begin())->getChar() == '[')
290                 return "\\\\[0pt]\n";
291
292         return "\\\\\n";
293 }
294
295
296 string MathGridInset::eocString(col_type col) const
297 {
298         if (col + 1 == ncols())
299                 return "";
300         return " & ";
301 }
302
303
304 void MathGridInset::addRow(row_type row)
305 {
306         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
307         cells_.insert(cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
308 }
309
310
311 void MathGridInset::appendRow()
312 {
313         rowinfo_.push_back(RowInfo());
314         for (col_type col = 0; col < ncols(); ++col)
315                 cells_.push_back(cells_type::value_type());
316 }
317
318
319 void MathGridInset::delRow(row_type row)
320 {
321         if (nrows() == 1)
322                 return;
323
324         cells_type::iterator it = cells_.begin() + row * ncols(); 
325         cells_.erase(it, it + ncols());
326
327         rowinfo_.erase(rowinfo_.begin() + row);
328 }
329
330
331 void MathGridInset::addCol(col_type newcol)
332 {
333         const col_type nc = ncols();
334         const row_type nr = nrows();
335         cells_type new_cells((nc + 1) * nr);
336         
337         for (row_type row = 0; row < nr; ++row)
338                 for (col_type col = 0; col < nc; ++col)
339                         new_cells[row * (nc + 1) + col + (col > newcol)]
340                                 = cells_[row * nc + col];
341         std::swap(cells_, new_cells);
342
343         ColInfo inf;
344         inf.skip_  = defaultColSpace(newcol);
345         inf.align_ = defaultColAlign(newcol);
346         colinfo_.insert(colinfo_.begin() + newcol, inf);
347 }
348
349
350 void MathGridInset::delCol(col_type col)
351 {
352         if (ncols() == 1)
353                 return;
354
355         cells_type tmpcells;
356         for (col_type i = 0; i < nargs(); ++i) 
357                 if (i % ncols() != col)
358                         tmpcells.push_back(cells_[i]);
359         std::swap(cells_, tmpcells);
360
361         colinfo_.erase(colinfo_.begin() + col);
362 }
363
364
365 int MathGridInset::cellXOffset(idx_type idx) const
366 {
367         col_type c = col(idx);
368         int x = colinfo_[c].offset_;
369         char align = colinfo_[c].align_;
370         if (align == 'r' || align == 'R')
371                 x += colinfo_[c].width_ - xcell(idx).width(); 
372         if (align == 'c' || align == 'C')
373                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2; 
374         return x;
375 }
376
377
378 int MathGridInset::cellYOffset(idx_type idx) const
379 {
380         return rowinfo_[row(idx)].offset_;
381 }
382
383
384 bool MathGridInset::idxUp(idx_type & idx, pos_type & pos) const
385 {
386         if (idx < ncols())
387                 return false;
388         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
389         idx -= ncols();
390         pos = xcell(idx).x2pos(x - cellXOffset(idx));
391         return true;
392 }
393
394         
395 bool MathGridInset::idxDown(idx_type & idx, pos_type & pos) const
396 {
397         if (idx >= ncols() * (nrows() - 1))
398                 return false;
399         int x = cellXOffset(idx) + xcell(idx).pos2x(pos);
400         idx += ncols();
401         pos = xcell(idx).x2pos(x - cellXOffset(idx));
402         return true;
403 }
404         
405         
406 bool MathGridInset::idxLeft(idx_type & idx, pos_type & pos) const
407 {
408         // leave matrix if on the left hand edge
409         if (col(idx) == 0)
410                 return false;
411         idx--;
412         pos = cell(idx).size();
413         return true;
414 }
415         
416         
417 bool MathGridInset::idxRight(idx_type & idx, pos_type & pos) const
418 {
419         // leave matrix if on the right hand edge
420         if (col(idx) == ncols() - 1)
421                 return false;
422         idx++;
423         pos = 0;
424         return true;
425 }
426
427
428 bool MathGridInset::idxFirst(idx_type & idx, pos_type & pos) const
429 {
430         switch (v_align_) {
431                 case 't':
432                         idx = 0;
433                         break;
434                 case 'b':
435                         idx = (nrows() - 1) * ncols();
436                         break;
437                 default: 
438                         idx = (nrows() / 2) * ncols();
439         }
440         pos = 0;
441         return true;
442 }
443
444
445 bool MathGridInset::idxLast(idx_type & idx, pos_type & pos) const
446 {
447         switch (v_align_) {
448                 case 't':
449                         idx = ncols() - 1;
450                         break;
451                 case 'b':
452                         idx = nargs() - 1;
453                         break;
454                 default:
455                         idx = (nrows() / 2 + 1) * ncols() - 1;
456         }
457         pos = cell(idx).size();
458         return true;
459 }
460
461
462 void MathGridInset::idxDelete(idx_type & idx, bool & popit, bool & deleteit)
463 {
464         popit    = false;
465         deleteit = false;
466
467         // delete entire sequence of ncols() empty cells if possible
468         if (idx <= index(nrows() - 1, 0))       {
469                 bool deleterow = true;
470                 for (idx_type i = idx; i < idx + ncols(); ++i)
471                         if (cell(i).size()) {
472                                 deleterow = false;
473                                 break;
474                         }
475
476                 if (deleterow) {
477                         // move cells if necessary
478                         for (idx_type i = index(row(idx), 0); i < idx; ++i)
479                                 cell(i).swap(cell(i + ncols()));
480                         
481                         delRow(row(idx));
482
483                         if (idx >= nargs())
484                                 idx = nargs() - 1;
485                         return;
486                 }
487         }
488
489         // undo effect of Ctrl-Tab (i.e. pull next cell)
490         //if (idx != nargs() - 1) 
491         //      cell(idx).swap(cell(idx + 1));
492 }
493
494
495 void MathGridInset::idxDeleteRange(idx_type /*from*/, idx_type /*to*/)
496 {
497 // leave this unimplemented unless someone wants to have it.
498 /*
499         int n = (to - from) / ncols();
500         int r = from / ncols();
501
502         if (n >= 1) {
503                 cells_type::iterator it = cells_.begin() + from;
504                 cells_.erase(it, it + n * ncols());
505                 rowinfo_.erase(rowinfo_.begin() + r, rowinfo_.begin() + r + n);
506         }
507 */
508 }
509
510
511 MathGridInset::RowInfo const & MathGridInset::rowinfo(row_type row) const
512 {
513         return rowinfo_[row];
514 }
515
516
517 MathGridInset::RowInfo & MathGridInset::rowinfo(row_type row)
518 {
519         return rowinfo_[row];
520 }
521
522
523 std::vector<MathInset::idx_type>
524         MathGridInset::idxBetween(idx_type from, idx_type to) const
525 {
526         row_type r1 = std::min(row(from), row(to));
527         row_type r2 = std::max(row(from), row(to));
528         col_type c1 = std::min(col(from), col(to));
529         col_type c2 = std::max(col(from), col(to));
530         std::vector<idx_type> res;
531         for (row_type i = r1; i <= r2; ++i)
532                 for (col_type j = c1; j <= c2; ++j)
533                         res.push_back(index(i, j));
534         return res;
535 }