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