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