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