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