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