]> git.lyx.org Git - features.git/blob - src/mathed/math_matrixinset.C
prepare re-enabling LaTeX feature validation
[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) const
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         features.boldsymbol = true;
234         //features.binom      = true;
235
236         MathInset::Validate(features);
237 }
238
239
240 void MathMatrixInset::header_write(std::ostream & os) const
241 {
242         bool n = numberedType();
243
244         switch (GetType()) {
245                 case LM_OT_SIMPLE:
246                         os << "\\("; 
247                         break;
248
249                 case LM_OT_EQUATION:
250                         if (n)
251                                 os << "\\begin{equation" << star(n) << "}\n"; 
252                         else
253                                 os << "\\[\n"; 
254                         break;
255
256                 case LM_OT_EQNARRAY:
257                         os << "\\begin{eqnarray" << star(n) << "}\n";
258                         break;
259
260                 case LM_OT_ALIGN:
261                         os << "\\begin{align" << star(n) << "}";
262                         break;
263
264                 case LM_OT_ALIGNAT:
265                         os << "\\begin{alignat" << star(n) << "}"
266                            << "{" << ncols()/2 << "}\n";
267                         break;
268                 default:
269                         os << "\\begin{unknown" << star(n) << "}";
270         }
271 }
272
273
274 void MathMatrixInset::footer_write(std::ostream & os) const
275 {
276         bool n = numberedType();
277
278         switch (GetType()) {
279                 case LM_OT_SIMPLE:
280                         os << "\\)";
281                         break;
282
283                 case LM_OT_EQUATION:
284                         if (n)
285                                 os << "\\end{equation" << star(n) << "}\n"; 
286                         else
287                                 os << "\\]\n"; 
288                         break;
289
290                 case LM_OT_EQNARRAY:
291                         os << "\\end{eqnarray" << star(n) << "}\n";
292                         break;
293
294                 case LM_OT_ALIGN:
295                         os << "\\end{align" << star(n) << "}\n";
296                         break;
297
298                 case LM_OT_ALIGNAT:
299                         os << "\\end{alignat" << star(n) << "}\n";
300                         break;
301
302                 default:
303                         os << "\\end{unknown" << star(n) << "}";
304         }
305 }
306
307
308 void MathMatrixInset::addRow(int row) 
309 {
310         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
311         label_.insert(label_.begin() + row + 1, string());
312         MathGridInset::addRow(row);
313 }
314
315 void MathMatrixInset::appendRow()
316 {
317         nonum_.push_back(!numberedType());
318         label_.push_back(string());
319         MathGridInset::appendRow();
320 }
321
322
323 void MathMatrixInset::delRow(int row) 
324 {
325         MathGridInset::delRow(row);
326         nonum_.erase(nonum_.begin() + row);
327         label_.erase(label_.begin() + row);
328 }
329
330 void MathMatrixInset::addCol(int col)
331 {
332         switch (GetType()) {
333                 case LM_OT_EQUATION:
334                         mutate(LM_OT_EQNARRAY);
335                         break;
336
337                 case LM_OT_EQNARRAY:
338                         mutate(LM_OT_ALIGN);
339                         addCol(col);
340                         break;
341
342                 case LM_OT_ALIGN:
343                 case LM_OT_ALIGNAT:
344                         MathGridInset::addCol(col);
345                         halign(col, 'l');
346                         MathGridInset::addCol(col);
347                         halign(col, 'r');
348                         break;
349
350                 default:
351                         break;
352         }
353 }
354
355 void MathMatrixInset::delCol(int col)
356 {
357         switch (GetType()) {
358                 case LM_OT_ALIGN:
359                         MathGridInset::delCol(col);
360                         break;
361
362                 default:
363                         break;
364         }
365 }
366
367
368 string MathMatrixInset::nicelabel(int row) const
369 {
370         if (nonum_[row])
371                 return string();
372         if (label_[row].empty())
373                 return string("(#)");
374         return "(" + label_[row] + ")";
375 }
376
377
378 namespace {
379         short typecode(string const & s)
380         {
381                 if (s == "equation")
382                         return LM_OT_EQUATION;
383                 if (s == "display")
384                         return LM_OT_EQUATION;
385                 if (s == "eqnarray")
386                         return LM_OT_EQNARRAY;
387                 if (s == "align")
388                         return LM_OT_ALIGN;
389                 if (s == "xalign")
390                         return LM_OT_XALIGN;
391                 if (s == "xxalign")
392                         return LM_OT_XXALIGN;
393                 if (s == "multline")
394                         return LM_OT_MULTLINE;
395                 return LM_OT_SIMPLE;
396         }       
397 }
398
399 void MathMatrixInset::mutate(string const & newtype)
400 {
401         if (newtype == "dump") {
402                 dump();
403                 return;
404         }
405         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
406         mutate(typecode(newtype));
407 }
408
409 void MathMatrixInset::glueall()
410 {
411         MathArray ar;
412         for (int i = 0; i < nargs(); ++i)
413                 ar.push_back(cell(i));
414         *this = MathMatrixInset(LM_OT_SIMPLE);
415         cell(0) = ar;
416 }
417
418 void MathMatrixInset::mutate(short newtype)
419 {
420         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
421
422         if (newtype == GetType())
423                 return;
424
425         switch (GetType()) {
426                 case LM_OT_SIMPLE:
427                         SetType(LM_OT_EQUATION);
428                         numbered(0, false);
429                         mutate(newtype);
430                         break;
431
432                 case LM_OT_EQUATION:
433                         switch (newtype) {
434                                 case LM_OT_SIMPLE:
435                                         SetType(LM_OT_SIMPLE);
436                                         break;
437
438                                 case LM_OT_ALIGN: {
439                                         MathGridInset::addCol(1);
440
441                                         // split it "nicely"
442                                         int pos = firstRelOp(cell(0));  
443                                         cell(1) = cell(0);
444                                         cell(0).erase(pos, cell(0).size());
445                                         cell(1).erase(0, pos);
446
447                                         halign("rl");
448                                         SetType(LM_OT_ALIGN);
449                                         break;
450                                 }
451
452                                 case LM_OT_EQNARRAY:
453                                 default:
454                                         MathGridInset::addCol(1);
455                                         MathGridInset::addCol(1);
456
457                                         // split it "nicely" on the firest relop
458                                         int pos1 = firstRelOp(cell(0)); 
459                                         cell(1) = cell(0);
460                                         cell(0).erase(pos1, cell(0).size());
461                                         cell(1).erase(0, pos1);
462                                         int pos2 = 0;
463                                         cell(1).next(pos2);
464                                         cell(2) = cell(1);
465                                         cell(1).erase(pos2, cell(1).size());
466                                         cell(2).erase(0, pos2);
467
468                                         halign("rcl");
469                                         SetType(LM_OT_EQNARRAY);
470                                         mutate(newtype);
471                                         break;
472                                 }
473                         break;
474
475                 case LM_OT_EQNARRAY:
476                         switch (newtype) {
477                                 case LM_OT_SIMPLE:
478                                 case LM_OT_EQUATION: {
479                                         // set correct (no)numbering
480                                         bool allnonum = true;
481                                         for (int r = 0; r < nrows(); ++r) {
482                                                 if (!nonum_[r])
483                                                         allnonum = false;
484                                         }
485
486                                         // set first non-empty label
487                                         string label;
488                                         for (int r = 0; r < nrows(); ++r) {
489                                                 if (!label_[r].empty()) {
490                                                         label = label_[r];
491                                                         break;
492                                                 }
493                                         }
494
495                                         glueall();
496
497                                         nonum_[0] = allnonum;
498                                         label_[0] = label;
499                                         mutate(newtype);
500                                         break;
501                                 }
502
503                                 case LM_OT_ALIGN:
504                                 default: {
505                                         for (int row = 0; row < nrows(); ++row) {
506                                                 int c = 3 * row + 1;
507                                                 cell(c).push_back(cell(c + 1));
508                                         }
509                                         MathGridInset::delCol(2);
510                                         SetType(LM_OT_ALIGN);
511                                         halign("rl");
512                                         mutate(newtype);
513                                         break;
514                                 }
515                         }
516                         break;
517
518                 case LM_OT_ALIGN:
519                         switch (newtype) {
520                                 case LM_OT_SIMPLE:
521                                 case LM_OT_EQUATION:
522                                 case LM_OT_EQNARRAY:
523                                         MathGridInset::addCol(1);
524                                         SetType(LM_OT_EQNARRAY);
525                                         halign("rcl");
526                                         mutate(newtype);
527                                         break;
528                                 
529                                 default:
530                                         lyxerr << "mutation from '" << GetType()
531                                                 << "' to '" << newtype << "' not implemented\n";
532                                         break;
533                         }
534                         break;
535
536                 default:
537                         lyxerr << "mutation from '" << GetType()
538                                 << "' to '" << newtype << "' not implemented\n";
539         }
540 }