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