]> git.lyx.org Git - features.git/blob - src/mathed/math_matrixinset.C
improve end-of-line handling in the presence of optional args to \\
[features.git] / src / mathed / math_matrixinset.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include <vector>
6
7 #include "math_matrixinset.h"
8 #include "support.h"
9 #include "debug.h"
10 #include "support/LOstream.h"
11 #include "Painter.h"
12 #include "LaTeXFeatures.h"
13
14
15 namespace {
16
17 string getAlign(MathInsetTypes type, int cols)
18 {
19         string align;
20         switch (type) {
21                 case LM_OT_ALIGN:
22                         for (int i = 0; i < cols; ++i)
23                                 align += "Rl";
24                         break;
25
26                 case LM_OT_ALIGNAT:
27                         for (int i = 0; i < cols; ++i)
28                                 align += "rl";
29                         break;
30
31                 case LM_OT_MULTLINE:
32                         align = "C";
33                         break;
34
35                 default:
36                         align = "rcl";
37                         break;
38         }
39         return align;
40 }
41
42
43 string const star(bool n)
44 {
45         return n ? "" : "*";
46 }
47
48
49 int getCols(short int type)
50 {
51         int col;
52         switch (type) {
53                 case LM_OT_EQNARRAY:
54                         col = 3;
55                         break;
56
57                 case LM_OT_ALIGN:
58                 case LM_OT_ALIGNAT:
59                         col = 2;
60                         break;
61
62                 default:
63                         col = 1;
64         }
65         return col;
66 }
67
68 // returns position of first relation operator in the array
69 // used for "intelligent splitting"
70 int firstRelOp(MathArray const & array)
71 {
72         for (MathArray::const_iterator it = array.begin(); it != array.end(); ++it)
73                 if ((*it)->isRelOp())
74                         return it - array.begin();
75         return array.size();
76 }
77
78 }
79
80 MathMatrixInset::MathMatrixInset(MathInsetTypes t)
81         : MathGridInset(getCols(t), 1), objtype_(t), nonum_(1), label_(1)
82 {
83         halign(getAlign(t, ncols()));
84 }
85
86
87 MathMatrixInset::MathMatrixInset()
88         : MathGridInset(1, 1), objtype_(LM_OT_SIMPLE), nonum_(1), label_(1)
89 {}
90
91 MathInset * MathMatrixInset::clone() const
92 {
93         return new MathMatrixInset(*this);
94 }
95
96
97 void MathMatrixInset::metrics(MathStyles) const
98 {
99         size_ = (getType() == LM_OT_SIMPLE) ? LM_ST_TEXT : LM_ST_DISPLAY;
100
101         // let the cells adjust themselves
102         MathGridInset::metrics(size_);
103
104         if (display()) {
105                 ascent_  += 12;
106                 descent_ += 12;
107         }       
108
109         if (numberedType()) {
110                 int l = 0;
111                 for (int row = 0; row < nrows(); ++row)
112                         l = std::max(l, mathed_string_width(LM_TC_BF, size(), nicelabel(row)));
113
114                 if (l)
115                         width_ += 30 + l;
116         }
117 }
118
119
120 void MathMatrixInset::draw(Painter & pain, int x, int y) const
121 {
122         xo(x);
123         yo(y);
124
125         MathGridInset::draw(pain, x, y);
126
127         if (numberedType()) {
128                 int xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
129                 for (int row = 0; row < nrows(); ++row) {
130                         int yy = y + rowinfo_[row].offset_;
131                         drawStr(pain, LM_TC_BF, size(), xx, yy, nicelabel(row));
132                 }
133         }
134 }
135
136
137 void MathMatrixInset::write(std::ostream & os, bool fragile) const
138 {
139   header_write(os);
140
141         bool n = numberedType();
142
143         for (int row = 0; row < nrows(); ++row) {
144                 for (int col = 0; col < ncols(); ++col) {
145                         os << eocString(col);
146                         cell(index(row, col)).write(os, fragile);
147                 }
148                 if (n) {
149                         if (!label_[row].empty())
150                                 os << "\\label{" << label_[row] << "}";
151                         if (nonum_[row])
152                                 os << "\\nonumber ";
153                 }
154                 os << eolString(row);
155         }
156
157   footer_write(os);
158 }
159
160
161 string MathMatrixInset::label(int row) const
162 {
163         return label_[row];
164 }
165
166 void MathMatrixInset::label(int row, string const & label)
167 {
168         label_[row] = label; 
169 }
170
171
172 void MathMatrixInset::numbered(int row, bool num)
173 {
174         nonum_[row] = !num; 
175 }
176
177
178 bool MathMatrixInset::numbered(int row) const
179 {
180         return !nonum_[row];
181 }
182
183
184 bool MathMatrixInset::ams() const
185 {
186         return true;
187 }
188
189
190 bool MathMatrixInset::display() const
191 {
192         return getType() != LM_OT_SIMPLE;
193 }
194
195
196 std::vector<string> const MathMatrixInset::getLabelList() const
197 {
198         std::vector<string> res;
199         for (int row = 0; row < nrows(); ++row)
200                 if (!label_[row].empty() && nonum_[row] != 1)
201                         res.push_back(label_[row]);
202         return res;
203 }
204
205
206 bool MathMatrixInset::numberedType() const
207 {
208         if (getType() == LM_OT_SIMPLE)
209                 return false;
210         for (int row = 0; row < nrows(); ++row)
211                 if (!nonum_[row])
212                         return true;
213         return false;
214 }
215
216
217 void MathMatrixInset::validate(LaTeXFeatures & features) const
218 {
219         features.amsstyle = ams();
220
221         // Validation is necessary only if not using AMS math.
222         // To be safe, we will always run mathedvalidate.
223         //if (features.amsstyle)
224         //  return;
225
226         features.boldsymbol = true;
227         //features.binom      = true;
228
229         MathNestInset::validate(features);
230 }
231
232
233 void MathMatrixInset::header_write(std::ostream & os) const
234 {
235         bool n = numberedType();
236
237         switch (getType()) {
238                 case LM_OT_SIMPLE:
239                         os << '$';
240                         if (cell(0).empty())
241                                 os << ' ';
242                         break;
243
244                 case LM_OT_EQUATION:
245                         if (n)
246                                 os << "\\begin{equation" << star(n) << "}\n"; 
247                         else
248                                 os << "\\[\n"; 
249                         break;
250
251                 case LM_OT_EQNARRAY:
252                         os << "\\begin{eqnarray" << star(n) << "}\n";
253                         break;
254
255                 case LM_OT_ALIGN:
256                         os << "\\begin{align" << star(n) << "}";
257                         break;
258
259                 case LM_OT_ALIGNAT:
260                         os << "\\begin{alignat" << star(n) << "}"
261                            << "{" << ncols()/2 << "}\n";
262                         break;
263                 default:
264                         os << "\\begin{unknown" << star(n) << "}";
265         }
266 }
267
268
269 void MathMatrixInset::footer_write(std::ostream & os) const
270 {
271         bool n = numberedType();
272
273         switch (getType()) {
274                 case LM_OT_SIMPLE:
275                         os << '$';
276                         break;
277
278                 case LM_OT_EQUATION:
279                         if (n)
280                                 os << "\\end{equation" << star(n) << "}\n"; 
281                         else
282                                 os << "\\]\n"; 
283                         break;
284
285                 case LM_OT_EQNARRAY:
286                         os << "\\end{eqnarray" << star(n) << "}\n";
287                         break;
288
289                 case LM_OT_ALIGN:
290                         os << "\\end{align" << star(n) << "}\n";
291                         break;
292
293                 case LM_OT_ALIGNAT:
294                         os << "\\end{alignat" << star(n) << "}\n";
295                         break;
296
297                 default:
298                         os << "\\end{unknown" << star(n) << "}";
299         }
300 }
301
302
303 void MathMatrixInset::addRow(int row) 
304 {
305         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
306         label_.insert(label_.begin() + row + 1, string());
307         MathGridInset::addRow(row);
308 }
309
310 void MathMatrixInset::appendRow()
311 {
312         nonum_.push_back(!numberedType());
313         label_.push_back(string());
314         MathGridInset::appendRow();
315 }
316
317
318 void MathMatrixInset::delRow(int row) 
319 {
320         MathGridInset::delRow(row);
321         nonum_.erase(nonum_.begin() + row);
322         label_.erase(label_.begin() + row);
323 }
324
325 void MathMatrixInset::addCol(int col)
326 {
327         switch (getType()) {
328                 case LM_OT_EQUATION:
329                         mutate(LM_OT_EQNARRAY);
330                         break;
331
332                 case LM_OT_EQNARRAY:
333                         mutate(LM_OT_ALIGN);
334                         addCol(col);
335                         break;
336
337                 case LM_OT_ALIGN:
338                 case LM_OT_ALIGNAT:
339                         MathGridInset::addCol(col);
340                         halign(col, 'l');
341                         MathGridInset::addCol(col);
342                         halign(col, 'r');
343                         break;
344
345                 default:
346                         break;
347         }
348 }
349
350 void MathMatrixInset::delCol(int col)
351 {
352         switch (getType()) {
353                 case LM_OT_ALIGN:
354                         MathGridInset::delCol(col);
355                         break;
356
357                 default:
358                         break;
359         }
360 }
361
362
363 string MathMatrixInset::nicelabel(int row) const
364 {
365         if (nonum_[row])
366                 return string();
367         if (label_[row].empty())
368                 return string("(#)");
369         return "(" + label_[row] + ")";
370 }
371
372
373 namespace {
374         short typecode(string const & s)
375         {
376                 if (s == "equation")
377                         return LM_OT_EQUATION;
378                 if (s == "display")
379                         return LM_OT_EQUATION;
380                 if (s == "eqnarray")
381                         return LM_OT_EQNARRAY;
382                 if (s == "align")
383                         return LM_OT_ALIGN;
384                 if (s == "xalign")
385                         return LM_OT_XALIGN;
386                 if (s == "xxalign")
387                         return LM_OT_XXALIGN;
388                 if (s == "multline")
389                         return LM_OT_MULTLINE;
390                 return LM_OT_SIMPLE;
391         }       
392 }
393
394 void MathMatrixInset::mutate(string const & newtype)
395 {
396         if (newtype == "dump") {
397                 dump();
398                 return;
399         }
400         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
401         mutate(typecode(newtype));
402 }
403
404 void MathMatrixInset::glueall()
405 {
406         MathArray ar;
407         for (int i = 0; i < nargs(); ++i)
408                 ar.push_back(cell(i));
409         *this = MathMatrixInset(LM_OT_SIMPLE);
410         cell(0) = ar;
411 }
412
413
414 MathInsetTypes MathMatrixInset::getType() const
415 {
416         return objtype_;
417 }
418
419
420 void MathMatrixInset::setType(MathInsetTypes t)
421 {
422         objtype_ = t;
423 }
424
425
426
427 void MathMatrixInset::mutate(short newtype)
428 {
429         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
430
431         if (newtype == getType())
432                 return;
433
434         switch (getType()) {
435                 case LM_OT_SIMPLE:
436                         setType(LM_OT_EQUATION);
437                         numbered(0, false);
438                         mutate(newtype);
439                         break;
440
441                 case LM_OT_EQUATION:
442                         switch (newtype) {
443                                 case LM_OT_SIMPLE:
444                                         setType(LM_OT_SIMPLE);
445                                         break;
446
447                                 case LM_OT_ALIGN: {
448                                         MathGridInset::addCol(1);
449
450                                         // split it "nicely"
451                                         int pos = firstRelOp(cell(0));  
452                                         cell(1) = cell(0);
453                                         cell(0).erase(pos, cell(0).size());
454                                         cell(1).erase(0, pos);
455
456                                         halign("rl");
457                                         setType(LM_OT_ALIGN);
458                                         break;
459                                 }
460
461                                 case LM_OT_EQNARRAY:
462                                 default:
463                                         MathGridInset::addCol(1);
464                                         MathGridInset::addCol(1);
465
466                                         // split it "nicely" on the firest relop
467                                         int pos = firstRelOp(cell(0));  
468                                         cell(1) = cell(0);
469                                         cell(0).erase(pos, cell(0).size());
470                                         cell(1).erase(0, pos);
471
472                                         if (cell(1).size()) {
473                                                 cell(2) = cell(1);
474                                                 cell(1).erase(1, cell(1).size());
475                                                 cell(2).erase(0);
476                                         }
477
478                                         halign("rcl");
479                                         setType(LM_OT_EQNARRAY);
480                                         mutate(newtype);
481                                         break;
482                                 }
483                         break;
484
485                 case LM_OT_EQNARRAY:
486                         switch (newtype) {
487                                 case LM_OT_SIMPLE:
488                                 case LM_OT_EQUATION: {
489                                         // set correct (no)numbering
490                                         bool allnonum = true;
491                                         for (int r = 0; r < nrows(); ++r) {
492                                                 if (!nonum_[r])
493                                                         allnonum = false;
494                                         }
495
496                                         // set first non-empty label
497                                         string label;
498                                         for (int r = 0; r < nrows(); ++r) {
499                                                 if (!label_[r].empty()) {
500                                                         label = label_[r];
501                                                         break;
502                                                 }
503                                         }
504
505                                         glueall();
506
507                                         nonum_[0] = allnonum;
508                                         label_[0] = label;
509                                         mutate(newtype);
510                                         break;
511                                 }
512
513                                 case LM_OT_ALIGN:
514                                 default: {
515                                         for (int row = 0; row < nrows(); ++row) {
516                                                 int c = 3 * row + 1;
517                                                 cell(c).push_back(cell(c + 1));
518                                         }
519                                         MathGridInset::delCol(2);
520                                         setType(LM_OT_ALIGN);
521                                         halign("rl");
522                                         mutate(newtype);
523                                         break;
524                                 }
525                         }
526                         break;
527
528                 case LM_OT_ALIGN:
529                         switch (newtype) {
530                                 case LM_OT_SIMPLE:
531                                 case LM_OT_EQUATION:
532                                 case LM_OT_EQNARRAY:
533                                         MathGridInset::addCol(1);
534                                         setType(LM_OT_EQNARRAY);
535                                         halign("rcl");
536                                         mutate(newtype);
537                                         break;
538                                 
539                                 default:
540                                         lyxerr << "mutation from '" << getType()
541                                                 << "' to '" << newtype << "' not implemented\n";
542                                         break;
543                         }
544                         break;
545
546                 default:
547                         lyxerr << "mutation from '" << getType()
548                                 << "' to '" << newtype << "' not implemented\n";
549         }
550 }