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