]> git.lyx.org Git - lyx.git/blob - src/mathed/math_hullinset.C
f08108e56191600f9faf2d2b0abe659ff7b83b01
[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         if (ams())
256                 features.require("amsstyle");
257
258
259         // Validation is necessary only if not using AMS math.
260         // To be safe, we will always run mathedvalidate.
261         //if (features.amsstyle)
262         //  return;
263
264         features.require("boldsymbol");
265         //features.binom      = true;
266
267         MathNestInset::validate(features);
268 }
269
270
271 void MathHullInset::header_write(WriteStream & os) const
272 {
273         bool n = numberedType();
274
275         switch (getType()) {
276                 case LM_OT_SIMPLE:
277                         os << '$';
278                         if (cell(0).empty())
279                                 os << ' ';
280                         break;
281
282                 case LM_OT_EQUATION:
283                         if (n)
284                                 os << "\\begin{equation" << star(n) << "}\n"; 
285                         else
286                                 os << "\\[\n"; 
287                         break;
288
289                 case LM_OT_EQNARRAY:
290                         os << "\\begin{eqnarray" << star(n) << "}\n";
291                         break;
292
293                 case LM_OT_ALIGN:
294                         os << "\\begin{align" << star(n) << "}\n";
295                         break;
296
297                 case LM_OT_ALIGNAT:
298                         os << "\\begin{alignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
299                         break;
300
301                 case LM_OT_XALIGNAT:
302                         os << "\\begin{xalignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
303                         break;
304
305                 case LM_OT_XXALIGNAT:
306                         os << "\\begin{xxalignat}" << "{" << ncols()/2 << "}\n";
307                         break;
308
309                 case LM_OT_MULTLINE:
310                         os << "\\begin{multline}\n";
311                         break;
312
313                 case LM_OT_GATHER:
314                         os << "\\begin{gather}\n";
315                         break;
316
317                 default:
318                         os << "\\begin{unknown" << star(n) << "}";
319         }
320 }
321
322
323 void MathHullInset::footer_write(WriteStream & os) const
324 {
325         bool n = numberedType();
326
327         switch (getType()) {
328                 case LM_OT_SIMPLE:
329                         os << '$';
330                         break;
331
332                 case LM_OT_EQUATION:
333                         if (n)
334                                 os << "\\end{equation" << star(n) << "}\n"; 
335                         else
336                                 os << "\\]\n"; 
337                         break;
338
339                 case LM_OT_EQNARRAY:
340                         os << "\n\\end{eqnarray" << star(n) << "}\n";
341                         break;
342
343                 case LM_OT_ALIGN:
344                         os << "\n\\end{align" << star(n) << "}\n";
345                         break;
346
347                 case LM_OT_ALIGNAT:
348                         os << "\n\\end{alignat" << star(n) << "}\n";
349                         break;
350
351                 case LM_OT_XALIGNAT:
352                         os << "\n\\end{xalignat" << star(n) << "}\n";
353                         break;
354
355                 case LM_OT_XXALIGNAT:
356                         os << "\n\\end{xxalignat}\n";
357                         break;
358
359                 case LM_OT_MULTLINE:
360                         os << "\n\\end{multline}\n";
361                         break;
362
363                 case LM_OT_GATHER:
364                         os << "\n\\end{gather}\n";
365                         break;
366
367                 default:
368                         os << "\\end{unknown" << star(n) << "}";
369         }
370 }
371
372
373 void MathHullInset::addRow(row_type row) 
374 {
375         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
376         label_.insert(label_.begin() + row + 1, string());
377         MathGridInset::addRow(row);
378 }
379
380
381 void MathHullInset::appendRow()
382 {
383         nonum_.push_back(!numberedType());
384         label_.push_back(string());
385         MathGridInset::appendRow();
386 }
387
388
389 void MathHullInset::delRow(row_type row) 
390 {
391         MathGridInset::delRow(row);
392         nonum_.erase(nonum_.begin() + row);
393         label_.erase(label_.begin() + row);
394 }
395
396
397 void MathHullInset::addCol(col_type col)
398 {
399         switch (getType()) {
400                 case LM_OT_EQUATION:
401                         mutate(LM_OT_EQNARRAY);
402                         break;
403
404                 case LM_OT_EQNARRAY:
405                         mutate(LM_OT_ALIGN);
406                         addCol(col);
407                         break;
408
409                 case LM_OT_ALIGN:
410                         mutate(LM_OT_ALIGNAT);
411                         addCol(col);
412                         break;
413
414                 case LM_OT_ALIGNAT:
415                 case LM_OT_XALIGNAT:
416                 case LM_OT_XXALIGNAT:
417                         MathGridInset::addCol(col);
418                         MathGridInset::addCol(col + 1);
419                         break;
420
421                 default:
422                         break;
423         }
424 }
425
426
427 void MathHullInset::delCol(col_type col)
428 {
429         switch (getType()) {
430                 case LM_OT_ALIGNAT:
431                 case LM_OT_XALIGNAT:
432                 case LM_OT_XXALIGNAT:
433                         MathGridInset::delCol(col + 1);
434                         MathGridInset::delCol(col);
435                         break;
436                 default:
437                         break;
438         }
439 }
440
441
442 string MathHullInset::nicelabel(row_type row) const
443 {
444         if (nonum_[row])
445                 return string();
446         if (label_[row].empty())
447                 return string("(#)");
448         return "(" + label_[row] + ")";
449 }
450
451
452 void MathHullInset::mutate(string const & newtype)
453 {
454         if (newtype == "dump") {
455                 dump();
456                 return;
457         }
458         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
459         mutate(typecode(newtype));
460 }
461
462
463 void MathHullInset::glueall()
464 {
465         MathArray ar;
466         for (idx_type i = 0; i < nargs(); ++i)
467                 ar.push_back(cell(i));
468         *this = MathHullInset(LM_OT_SIMPLE);
469         cell(0) = ar;
470 }
471
472
473 MathInsetTypes MathHullInset::getType() const
474 {
475         return objtype_;
476 }
477
478
479 void MathHullInset::setType(MathInsetTypes t)
480 {
481         objtype_ = t;
482         setDefaults();
483 }
484
485
486
487 void MathHullInset::mutate(MathInsetTypes newtype)
488 {
489         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
490
491         if (newtype == getType())
492                 return;
493
494         switch (getType()) {
495                 case LM_OT_SIMPLE:
496                         setType(LM_OT_EQUATION);
497                         numbered(0, false);
498                         mutate(newtype);
499                         break;
500
501                 case LM_OT_EQUATION:
502                         switch (newtype) {
503                                 case LM_OT_SIMPLE:
504                                         setType(LM_OT_SIMPLE);
505                                         break;
506
507                                 case LM_OT_ALIGN: 
508                                 case LM_OT_ALIGNAT:
509                                 case LM_OT_XALIGNAT:
510                                 case LM_OT_XXALIGNAT: {
511
512                                         MathGridInset::addCol(1);
513
514                                         // split it "nicely"
515                                         pos_type pos = firstRelOp(cell(0));     
516                                         cell(1) = cell(0);
517                                         cell(0).erase(pos, cell(0).size());
518                                         cell(1).erase(0, pos);
519                                         setType(LM_OT_ALIGN);
520                                         mutate(newtype);
521                                         break;
522                                 }
523
524                                 case LM_OT_EQNARRAY:
525                                 default:
526                                         MathGridInset::addCol(1);
527                                         MathGridInset::addCol(1);
528
529                                         // split it "nicely" on the firest relop
530                                         pos_type pos = firstRelOp(cell(0));     
531                                         cell(1) = MathArray(cell(0), pos, cell(0).size());
532                                         cell(0).erase(pos, cell(0).size());
533
534                                         if (cell(1).size()) {
535                                                 cell(2) = MathArray(cell(1), 1, cell(1).size());
536                                                 cell(1).erase(1, cell(1).size());
537                                         }
538
539                                         setType(LM_OT_EQNARRAY);
540                                         mutate(newtype);
541                                         break;
542                                 }
543                         break;
544
545                 case LM_OT_EQNARRAY:
546                         switch (newtype) {
547                                 case LM_OT_SIMPLE:
548                                 case LM_OT_EQUATION: {
549                                         // set correct (no)numbering
550                                         bool allnonum = true;
551                                         for (row_type row = 0; row < nrows(); ++row) {
552                                                 if (!nonum_[row])
553                                                         allnonum = false;
554                                         }
555
556                                         // set first non-empty label
557                                         string label;
558                                         for (row_type row = 0; row < nrows(); ++row) {
559                                                 if (!label_[row].empty()) {
560                                                         label = label_[row];
561                                                         break;
562                                                 }
563                                         }
564
565                                         glueall();
566
567                                         nonum_[0] = allnonum;
568                                         label_[0] = label;
569                                         mutate(newtype);
570                                         break;
571                                 }
572
573                                 case LM_OT_ALIGN:
574                                 case LM_OT_ALIGNAT:
575                                 case LM_OT_XALIGNAT:
576                                 case LM_OT_XXALIGNAT:
577                                 default: {
578                                         for (row_type row = 0; row < nrows(); ++row) {
579                                                 idx_type c = 3 * row + 1;
580                                                 cell(c).push_back(cell(c + 1));
581                                         }
582                                         MathGridInset::delCol(2);
583                                         setType(LM_OT_ALIGN);
584                                         mutate(newtype);
585                                         break;
586                                 }
587                         }
588                         break;
589
590                 case LM_OT_ALIGN:
591                         switch (newtype) {
592                                 case LM_OT_SIMPLE:
593                                 case LM_OT_EQUATION:
594                                 case LM_OT_EQNARRAY:
595                                         MathGridInset::addCol(1);
596                                         setType(LM_OT_EQNARRAY);
597                                         mutate(newtype);
598                                         break;
599                                 
600                                 case LM_OT_ALIGNAT:
601                                 case LM_OT_XALIGNAT:
602                                 case LM_OT_XXALIGNAT:
603                                         setType(newtype);
604                                         break;
605
606                                 default:
607                                         lyxerr << "mutation from '" << getType()
608                                                 << "' to '" << newtype << "' not implemented\n";
609                                         break;
610                         }
611                         break;
612
613                 case LM_OT_MULTLINE:
614                         switch (newtype) {
615                                 case LM_OT_GATHER:
616                                         setType(LM_OT_GATHER);
617                                         break;
618                                 default:
619                                         lyxerr << "mutation from '" << getType()
620                                                 << "' to '" << newtype << "' not implemented\n";
621                                         break;
622                         }
623
624                 case LM_OT_GATHER:
625                         switch (newtype) {
626                                 case LM_OT_MULTLINE:
627                                         setType(LM_OT_MULTLINE);
628                                         break;
629                                 default:
630                                         lyxerr << "mutation from '" << getType()
631                                                 << "' to '" << newtype << "' not implemented\n";
632                                         break;
633                         }
634
635                 default:
636                         lyxerr << "mutation from '" << getType()
637                                 << "' to '" << newtype << "' not implemented\n";
638         }
639 }
640
641
642 void MathHullInset::write(WriteStream & os) const
643 {
644   header_write(os);
645
646         bool n = numberedType();
647
648         for (row_type row = 0; row < nrows(); ++row) {
649                 for (col_type col = 0; col < ncols(); ++col) 
650                         os << cell(index(row, col)) << eocString(col).c_str();
651                 if (n) {
652                         if (!label_[row].empty())
653                                 os << "\\label{" << label_[row].c_str() << "}";
654                         if (nonum_[row])
655                                 os << "\\nonumber ";
656                 }
657                 os << eolString(row).c_str();
658         }
659
660   footer_write(os);
661 }
662
663
664 void MathHullInset::normalize(NormalStream & os) const
665 {
666         os << "[formula " << normalName(getType()).c_str() << " ";
667         MathGridInset::normalize(os);
668         os << "] ";
669 }
670
671
672 void MathHullInset::mathmlize(MathMLStream & os) const
673 {
674         MathGridInset::mathmlize(os);
675 }
676
677