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