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