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