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