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