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