]> git.lyx.org Git - lyx.git/blob - src/mathed/math_gridinset.C
some support for the [x][x]alignat environments
[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 MathGridInset::RowInfo::RowInfo()
23         : upperline_(false), lowerline_(false)
24 {}
25
26
27 int MathGridInset::RowInfo::skipPixels() const
28 {
29 #ifdef WITH_WARNINGS
30 #warning fix this once the interface to LyXLength has improved
31 #endif
32         return int(skip_.value());
33 }
34
35
36
37 MathGridInset::ColInfo::ColInfo()
38         : align_('c'), leftline_(false), rightline_(false), skip_(MATH_COLSEP)
39 {}
40
41
42 MathGridInset::MathGridInset(int m, int n)
43         : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_('c')
44 {
45         if (m <= 0)
46                 lyxerr << "positve number of columns expected\n";
47         if (n <= 0)
48                 lyxerr << "positve number of rows expected\n";
49         for (int col = 0; col < m; ++col) {
50                 colinfo_[col].skip_  = defaultColSpace(col);
51                 colinfo_[col].align_ = defaultColAlign(col);
52         }
53 }
54
55
56 int MathGridInset::index(int row, int col) const
57 {
58         return col + ncols() * row;
59 }
60
61
62
63 void MathGridInset::halign(string const & hh)
64 {
65         int n = hh.size();
66         if (n > ncols())
67                 n = ncols();
68         for (int i = 0; i < n; ++i)
69                 colinfo_[i].align_ = hh[i];
70 }
71
72
73 void MathGridInset::halign(char h, int col)
74 {
75         colinfo_[col].align_ = h;
76 }
77
78
79 char MathGridInset::halign(int col) const
80 {
81         return colinfo_[col].align_;
82 }
83
84
85
86 void MathGridInset::valign(char c)
87 {
88         v_align_ = c;
89 }
90
91
92 char MathGridInset::valign() const
93 {
94         return v_align_;
95 }
96
97
98
99 void MathGridInset::vskip(LyXLength const & skip, int row)
100 {
101         rowinfo_[row].skip_ = skip;
102 }
103
104
105 LyXLength MathGridInset::vskip(int row) const
106 {
107         return rowinfo_[row].skip_;
108 }
109
110
111 void MathGridInset::metrics(MathStyles st) const
112 {
113         // let the cells adjust themselves
114         MathNestInset::metrics(st);
115         size_ = st;
116
117         // adjust vertical structure
118         for (int row = 0; row < nrows(); ++row) {
119                 int asc  = 0;
120                 int desc = 0;
121                 for (int col = 0; col < ncols(); ++col) {
122                         MathXArray const & c = xcell(index(row, col));
123                         asc  = std::max(asc,  c.ascent());
124                         desc = std::max(desc, c.descent());
125                 }
126                 rowinfo_[row].ascent_  = asc;
127                 rowinfo_[row].descent_ = desc;
128
129                 if (row) 
130                         rowinfo_[row].offset_ = 
131                                 rowinfo_[row - 1].offset_ +
132                                 rowinfo_[row - 1].descent_ +
133                                 rowinfo_[row - 1].skipPixels() +
134                                 MATH_ROWSEP +
135                                 rowinfo_[row].ascent_;
136                 else 
137                         rowinfo_[row].offset_ = 0;
138         }
139
140         // adjust vertical offset
141         int h = 0;
142         switch (v_align_) {
143         case 't':
144                 h = 0;
145                 break;
146         case 'b':
147                 h = rowinfo_.back().offset_;
148                 break;
149         default:
150                 h = rowinfo_.back().offset_ / 2;
151         }
152
153         for (int row = 0; row < nrows(); ++row) {
154                 rowinfo_[row].offset_ -= h;
155                 rowinfo_[row].offset_ += MATH_BORDER;
156         }
157         
158         // adjust horizontal structure
159         for (int col = 0; col < ncols(); ++col) {
160                 int wid  = 0;
161                 for (int row = 0; row < nrows(); ++row) 
162                         wid = std::max(wid, xcell(index(row, col)).width());
163                 colinfo_[col].width_  = wid;
164                 colinfo_[col].offset_ = colinfo_[col].width_;
165
166                 if (col) 
167                         colinfo_[col].offset_ =
168                                 colinfo_[col - 1].offset_ +
169                                 colinfo_[col - 1].width_ + 
170                                 colinfo_[col - 1].skip_;
171                 else
172                         colinfo_[col].offset_ = 0;
173
174                 colinfo_[col].offset_ += MATH_BORDER;
175         }
176
177         width_   =   colinfo_.back().offset_  + colinfo_.back().width_;
178         ascent_  = - rowinfo_.front().offset_ + rowinfo_.front().ascent_;
179         descent_ =   rowinfo_.back().offset_  + rowinfo_.back().descent_;
180         
181 /*      
182         // Increase ws_[i] for 'R' columns (except the first one)
183         for (int i = 1; i < nc_; ++i)
184                 if (align_[i] == 'R')
185                         ws_[i] += 10 * df_width;
186         // Increase ws_[i] for 'C' column
187         if (align_[0] == 'C')
188                 if (ws_[0] < 7 * workwidth / 8)
189                         ws_[0] = 7 * workwidth / 8;
190         
191         // Adjust local tabs
192         width = MATH_COLSEP;
193         for (cxrow = row_.begin(); cxrow; ++cxrow) {   
194                 int rg = MATH_COLSEP;
195                 int lf = 0;
196                 for (int i = 0; i < nc_; ++i) {
197                         bool isvoid = false;
198                         if (cxrow->getTab(i) <= 0) {
199                                 cxrow->setTab(i, df_width);
200                                 isvoid = true;
201                         }
202                         switch (align_[i]) {
203                         case 'l':
204                                 lf = 0;
205                                 break;
206                         case 'c':
207                                 lf = (ws_[i] - cxrow->getTab(i))/2; 
208                                 break;
209                         case 'r':
210                         case 'R':
211                                 lf = ws_[i] - cxrow->getTab(i);
212                                 break;
213                         case 'C':
214                                 if (cxrow == row_.begin())
215                                         lf = 0;
216                                 else if (cxrow.is_last())
217                                         lf = ws_[i] - cxrow->getTab(i);
218                                 else
219                                         lf = (ws_[i] - cxrow->getTab(i))/2; 
220                                 break;
221                         }
222                         int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
223                         cxrow->setTab(i, lf + rg);
224                         rg = ws_[i] - ww + MATH_COLSEP;
225                         if (cxrow == row_.begin())
226                                 width += ws_[i] + MATH_COLSEP;
227                 }
228                 cxrow->setBaseline(cxrow->getBaseline() - ascent);
229         }
230 */
231 }
232
233
234 void MathGridInset::draw(Painter & pain, int x, int y) const
235 {
236         xo(x);
237         yo(y);
238         for (int idx = 0; idx < nargs(); ++idx)
239                 xcell(idx).draw(pain, x + cellXOffset(idx), y + cellYOffset(idx));
240 }
241
242
243 void MathGridInset::write(std::ostream & os, bool fragile) const
244 {
245         for (int row = 0; row < nrows(); ++row) {
246                 for (int col = 0; col < ncols(); ++col) {
247                         cell(index(row, col)).write(os, fragile);
248                         os << eocString(col);
249                 }
250                 os << eolString(row);
251         }
252 }
253
254
255 string MathGridInset::eolString(int row) const
256 {
257         if (row == nrows() - 1) 
258                 return "";
259
260         if (rowinfo_[row].skip_.value() != 0)
261                 return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n";
262
263         // make sure an upcoming '[' does not break anything
264         MathArray const & c = cell(index(row + 1, 0));
265         if (c.size() && (*c.begin())->getChar() == '[')
266                 return "\\\\[0pt]\n";
267
268         return "\\\\\n";
269 }
270
271
272 string MathGridInset::eocString(int col) const
273 {
274         if (col == ncols() - 1)
275                 return "";
276         return " & ";
277 }
278
279
280 void MathGridInset::addRow(int row)
281 {
282         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
283         cells_.insert(cells_.begin() + (row + 1) * ncols(), ncols(), MathXArray());
284 }
285
286
287 void MathGridInset::appendRow()
288 {
289         rowinfo_.push_back(RowInfo());
290         for (int i = 0; i < ncols(); ++i)
291                 cells_.push_back(cells_type::value_type());
292 }
293
294
295 void MathGridInset::delRow(int row)
296 {
297         if (nrows() == 1)
298                 return;
299
300         cells_type::iterator it = cells_.begin() + row * ncols(); 
301         cells_.erase(it, it + ncols());
302
303         rowinfo_.erase(rowinfo_.begin() + row);
304 }
305
306
307 void MathGridInset::addCol(int newcol)
308 {
309         int const nc = ncols();
310         int const nr = nrows();
311         cells_type new_cells((nc + 1) * nr);
312         
313         for (int row = 0; row < nr; ++row)
314                 for (int col = 0; col < nc; ++col)
315                         new_cells[row * (nc + 1) + col + (col > newcol)]
316                                 = cells_[row * nc + col];
317         std::swap(cells_, new_cells);
318
319         ColInfo inf;
320         inf.skip_  = defaultColSpace(newcol);
321         inf.align_ = defaultColAlign(newcol);
322         colinfo_.insert(colinfo_.begin() + newcol, inf);
323 }
324
325
326 void MathGridInset::delCol(int col)
327 {
328         if (ncols() == 1)
329                 return;
330
331         cells_type tmpcells;
332         for (int i = 0; i < nargs(); ++i) 
333                 if (i % ncols() != col)
334                         tmpcells.push_back(cells_[i]);
335         std::swap(cells_, tmpcells);
336
337         colinfo_.erase(colinfo_.begin() + col);
338 }
339
340
341 int MathGridInset::cellXOffset(int idx) const
342 {
343         int c = col(idx);
344         int x = colinfo_[c].offset_;
345         char align = colinfo_[c].align_;
346         if (align == 'r' || align == 'R')
347                 x += colinfo_[c].width_ - xcell(idx).width(); 
348         if (align == 'c' || align == 'C')
349                 x += (colinfo_[c].width_ - xcell(idx).width()) / 2; 
350         return x;
351 }
352
353
354 int MathGridInset::cellYOffset(int idx) const
355 {
356         return rowinfo_[row(idx)].offset_;
357 }
358
359
360 bool MathGridInset::idxUp(int & idx, int & pos) const
361 {
362         if (idx < ncols())
363                 return false;
364         idx -= ncols();
365         pos = 0;
366         return true;
367 }
368
369         
370 bool MathGridInset::idxDown(int & idx, int & pos) const
371 {
372         if (idx >= ncols() * (nrows() - 1))
373                 return false;
374         idx += ncols();
375         pos = 0;
376         return true;
377 }
378         
379         
380 bool MathGridInset::idxLeft(int & idx, int & pos) const
381 {
382         // leave matrix if on the left hand edge
383         if (col(idx) == 0)
384                 return false;
385         idx--;
386         pos = cell(idx).size();
387         return true;
388 }
389         
390         
391 bool MathGridInset::idxRight(int & idx, int & pos) const
392 {
393         // leave matrix if on the right hand edge
394         if (col(idx) == ncols() - 1)
395                 return false;
396         idx++;
397         pos = 0;
398         return true;
399 }
400
401
402 bool MathGridInset::idxFirst(int & idx, int & pos) const
403 {
404         switch (v_align_) {
405                 case 't':
406                         idx = 0;
407                         break;
408                 case 'b':
409                         idx = (nrows() - 1) * ncols();
410                         break;
411                 default: 
412                         idx = (nrows() / 2) * ncols();
413         }
414         pos = 0;
415         return true;
416 }
417
418
419 bool MathGridInset::idxLast(int & idx, int & pos) const
420 {
421         switch (v_align_) {
422                 case 't':
423                         idx = ncols() - 1;
424                         break;
425                 case 'b':
426                         idx = nargs() - 1;
427                         break;
428                 default:
429                         idx = (nrows() / 2 + 1) * ncols() - 1;
430         }
431         pos = cell(idx).size();
432         return true;
433 }
434
435
436 void MathGridInset::idxDelete(int & idx, bool & popit, bool & deleteit)
437 {
438         popit    = false;
439         deleteit = false;
440
441         // delete entire row if in first cell of empty row
442         if (col(idx) == 0 && nrows() > 1) {
443                 bool deleterow = true;
444                 for (int i = idx; i < idx + ncols(); ++i)
445                         if (cell(i).size()) {
446                                 deleterow = false;
447                                 break;
448                         }
449                 if (deleterow) 
450                         delRow(row(idx));
451
452                 if (idx >= nargs())
453                         idx = nargs() - 1;
454                 return;
455         }
456
457         // undo effect of Ctrl-Tab (i.e. pull next cell)
458         //if (idx != nargs() - 1) 
459         //      cell(idx).swap(cell(idx + 1));
460 }
461
462
463 void MathGridInset::idxDeleteRange(int /*from*/, int /*to*/)
464 {
465 // leave this unimplemented unless someone wants to have it.
466 /*
467         int n = (to - from) / ncols();
468         int r = from / ncols();
469
470         if (n >= 1) {
471                 cells_type::iterator it = cells_.begin() + from;
472                 cells_.erase(it, it + n * ncols());
473                 rowinfo_.erase(rowinfo_.begin() + r, rowinfo_.begin() + r + n);
474         }
475 */
476 }
477
478
479 MathGridInset::RowInfo const & MathGridInset::rowinfo(int i) const
480 {
481         return rowinfo_[i];
482 }
483
484
485 MathGridInset::RowInfo & MathGridInset::rowinfo(int i)
486 {
487         return rowinfo_[i];
488 }
489
490
491 std::vector<int> MathGridInset::idxBetween(int from, int to) const
492 {
493         int r1 = std::min(row(from), row(to));
494         int r2 = std::max(row(from), row(to));
495         int c1 = std::min(col(from), col(to));
496         int c2 = std::max(col(from), col(to));
497         std::vector<int> res;
498         for (int i = r1; i <= r2; ++i)
499                 for (int j = c1; j <= c2; ++j)
500                         res.push_back(index(i, j));
501         return res;
502 }