]> git.lyx.org Git - features.git/blob - src/mathed/math_matrixinset.C
5e61d8671e24023ddaf973a7d2a7ed2595a6e7d3
[features.git] / src / mathed / math_matrixinset.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include <vector>
6
7 #include "math_matrixinset.h"
8 #include "support.h"
9 #include "debug.h"
10 #include "support/LOstream.h"
11 #include "Painter.h"
12 #include "LaTeXFeatures.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 MathMatrixInset::MathMatrixInset()
85         : MathGridInset(1, 1), objtype_(LM_OT_SIMPLE), nonum_(1), label_(1)
86 {
87         setDefaults();
88 }
89
90
91 MathMatrixInset::MathMatrixInset(MathInsetTypes t)
92         : MathGridInset(getCols(t), 1), objtype_(t), nonum_(1), label_(1)
93 {
94         setDefaults();
95 }
96
97
98 MathMatrixInset::MathMatrixInset(MathInsetTypes t, col_type cols)
99         : MathGridInset(cols, 1), objtype_(t), nonum_(1), label_(1)
100 {
101         setDefaults();
102 }
103
104
105 MathInset * MathMatrixInset::clone() const
106 {
107         return new MathMatrixInset(*this);
108 }
109
110
111 char MathMatrixInset::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 MathMatrixInset::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 MathMatrixInset::metrics(MathStyles) const
144 {
145         size_ = (getType() == LM_OT_SIMPLE) ? LM_ST_TEXT : LM_ST_DISPLAY;
146
147         // let the cells adjust themselves
148         MathGridInset::metrics(size_);
149
150         if (display()) {
151                 ascent_  += 12;
152                 descent_ += 12;
153         }       
154
155         if (numberedType()) {
156                 int l = 0;
157                 for (row_type row = 0; row < nrows(); ++row)
158                         l = std::max(l, mathed_string_width(LM_TC_BF, size(), nicelabel(row)));
159
160                 if (l)
161                         width_ += 30 + l;
162         }
163
164         // make it at least as high as the current font
165         int asc = 0;
166         int des = 0;
167         math_font_max_dim(LM_TC_TEXTRM, LM_ST_TEXT, asc, des);
168         ascent_  = std::max(ascent_,  asc);
169         descent_ = std::max(descent_, des);
170 }
171
172
173 void MathMatrixInset::draw(Painter & pain, int x, int y) const
174 {
175         xo(x);
176         yo(y);
177
178         MathGridInset::draw(pain, x, y);
179
180         if (numberedType()) {
181                 int xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
182                 for (row_type row = 0; row < nrows(); ++row) {
183                         int yy = y + rowinfo_[row].offset_;
184                         drawStr(pain, LM_TC_BF, size(), xx, yy, nicelabel(row));
185                 }
186         }
187 }
188
189
190 void MathMatrixInset::write(std::ostream & os, bool fragile) const
191 {
192   header_write(os);
193
194         bool n = numberedType();
195
196         for (row_type row = 0; row < nrows(); ++row) {
197                 for (col_type col = 0; col < ncols(); ++col) {
198                         cell(index(row, col)).write(os, fragile);
199                         os << eocString(col);
200                 }
201                 if (n) {
202                         if (!label_[row].empty())
203                                 os << "\\label{" << label_[row] << "}";
204                         if (nonum_[row])
205                                 os << "\\nonumber ";
206                 }
207                 os << eolString(row);
208         }
209
210   footer_write(os);
211 }
212
213
214 void MathMatrixInset::writeNormal(std::ostream & os) const
215 {
216         os << "[formula " << normalName(getType()) << " ";
217         MathGridInset::writeNormal(os);
218         os << "] ";
219 }
220
221
222
223 string MathMatrixInset::label(row_type row) const
224 {
225         return label_[row];
226 }
227
228
229 void MathMatrixInset::label(row_type row, string const & label)
230 {
231         label_[row] = label; 
232 }
233
234
235 void MathMatrixInset::numbered(row_type row, bool num)
236 {
237         nonum_[row] = !num; 
238 }
239
240
241 bool MathMatrixInset::numbered(row_type row) const
242 {
243         return !nonum_[row];
244 }
245
246
247 bool MathMatrixInset::ams() const
248 {
249         return true;
250 }
251
252
253 bool MathMatrixInset::display() const
254 {
255         return getType() != LM_OT_SIMPLE;
256 }
257
258
259 std::vector<string> const MathMatrixInset::getLabelList() const
260 {
261         std::vector<string> res;
262         for (row_type row = 0; row < nrows(); ++row)
263                 if (!label_[row].empty() && nonum_[row] != 1)
264                         res.push_back(label_[row]);
265         return res;
266 }
267
268
269 bool MathMatrixInset::numberedType() const
270 {
271         if (getType() == LM_OT_SIMPLE || getType() == LM_OT_XXALIGNAT)
272                 return false;
273         for (row_type row = 0; row < nrows(); ++row)
274                 if (!nonum_[row])
275                         return true;
276         return false;
277 }
278
279
280 void MathMatrixInset::validate(LaTeXFeatures & features) const
281 {
282         features.amsstyle = ams();
283
284         // Validation is necessary only if not using AMS math.
285         // To be safe, we will always run mathedvalidate.
286         //if (features.amsstyle)
287         //  return;
288
289         features.boldsymbol = true;
290         //features.binom      = true;
291
292         MathNestInset::validate(features);
293 }
294
295
296 void MathMatrixInset::header_write(std::ostream & os) const
297 {
298         bool n = numberedType();
299
300         switch (getType()) {
301                 case LM_OT_SIMPLE:
302                         os << '$';
303                         if (cell(0).empty())
304                                 os << ' ';
305                         break;
306
307                 case LM_OT_EQUATION:
308                         if (n)
309                                 os << "\\begin{equation" << star(n) << "}\n"; 
310                         else
311                                 os << "\\[\n"; 
312                         break;
313
314                 case LM_OT_EQNARRAY:
315                         os << "\\begin{eqnarray" << star(n) << "}\n";
316                         break;
317
318                 case LM_OT_ALIGN:
319                         os << "\\begin{align" << star(n) << "}\n";
320                         break;
321
322                 case LM_OT_ALIGNAT:
323                         os << "\\begin{alignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
324                         break;
325
326                 case LM_OT_XALIGNAT:
327                         os << "\\begin{xalignat" << star(n) << "}" << "{" << ncols()/2 << "}\n";
328                         break;
329
330                 case LM_OT_XXALIGNAT:
331                         os << "\\begin{xxalignat}" << "{" << ncols()/2 << "}\n";
332                         break;
333
334                 case LM_OT_MULTLINE:
335                         os << "\\begin{multline}\n";
336                         break;
337
338                 case LM_OT_GATHER:
339                         os << "\\begin{gather}\n";
340                         break;
341
342                 default:
343                         os << "\\begin{unknown" << star(n) << "}";
344         }
345 }
346
347
348 void MathMatrixInset::footer_write(std::ostream & os) const
349 {
350         bool n = numberedType();
351
352         switch (getType()) {
353                 case LM_OT_SIMPLE:
354                         os << '$';
355                         break;
356
357                 case LM_OT_EQUATION:
358                         if (n)
359                                 os << "\\end{equation" << star(n) << "}\n"; 
360                         else
361                                 os << "\\]\n"; 
362                         break;
363
364                 case LM_OT_EQNARRAY:
365                         os << "\n\\end{eqnarray" << star(n) << "}\n";
366                         break;
367
368                 case LM_OT_ALIGN:
369                         os << "\n\\end{align" << star(n) << "}\n";
370                         break;
371
372                 case LM_OT_ALIGNAT:
373                         os << "\n\\end{alignat" << star(n) << "}\n";
374                         break;
375
376                 case LM_OT_XALIGNAT:
377                         os << "\n\\end{xalignat" << star(n) << "}\n";
378                         break;
379
380                 case LM_OT_XXALIGNAT:
381                         os << "\n\\end{xxalignat}\n";
382                         break;
383
384                 case LM_OT_MULTLINE:
385                         os << "\n\\end{multline}\n";
386                         break;
387
388                 case LM_OT_GATHER:
389                         os << "\n\\end{gather}\n";
390                         break;
391
392                 default:
393                         os << "\\end{unknown" << star(n) << "}";
394         }
395 }
396
397
398 void MathMatrixInset::addRow(row_type row) 
399 {
400         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
401         label_.insert(label_.begin() + row + 1, string());
402         MathGridInset::addRow(row);
403 }
404
405
406 void MathMatrixInset::appendRow()
407 {
408         nonum_.push_back(!numberedType());
409         label_.push_back(string());
410         MathGridInset::appendRow();
411 }
412
413
414 void MathMatrixInset::delRow(row_type row) 
415 {
416         MathGridInset::delRow(row);
417         nonum_.erase(nonum_.begin() + row);
418         label_.erase(label_.begin() + row);
419 }
420
421
422 void MathMatrixInset::addCol(col_type col)
423 {
424         switch (getType()) {
425                 case LM_OT_EQUATION:
426                         mutate(LM_OT_EQNARRAY);
427                         break;
428
429                 case LM_OT_EQNARRAY:
430                         mutate(LM_OT_ALIGN);
431                         addCol(col);
432                         break;
433
434                 case LM_OT_ALIGN:
435                         mutate(LM_OT_ALIGNAT);
436                         addCol(col);
437                         break;
438
439                 case LM_OT_ALIGNAT:
440                 case LM_OT_XALIGNAT:
441                 case LM_OT_XXALIGNAT:
442                         MathGridInset::addCol(col);
443                         MathGridInset::addCol(col + 1);
444                         break;
445
446                 default:
447                         break;
448         }
449 }
450
451
452 void MathMatrixInset::delCol(col_type col)
453 {
454         switch (getType()) {
455                 case LM_OT_ALIGNAT:
456                 case LM_OT_XALIGNAT:
457                 case LM_OT_XXALIGNAT:
458                         MathGridInset::delCol(col + 1);
459                         MathGridInset::delCol(col);
460                         break;
461                 default:
462                         break;
463         }
464 }
465
466
467 string MathMatrixInset::nicelabel(row_type row) const
468 {
469         if (nonum_[row])
470                 return string();
471         if (label_[row].empty())
472                 return string("(#)");
473         return "(" + label_[row] + ")";
474 }
475
476
477 void MathMatrixInset::mutate(string const & newtype)
478 {
479         if (newtype == "dump") {
480                 dump();
481                 return;
482         }
483         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
484         mutate(typecode(newtype));
485 }
486
487
488 void MathMatrixInset::glueall()
489 {
490         MathArray ar;
491         for (idx_type i = 0; i < nargs(); ++i)
492                 ar.push_back(cell(i));
493         *this = MathMatrixInset(LM_OT_SIMPLE);
494         cell(0) = ar;
495 }
496
497
498 MathInsetTypes MathMatrixInset::getType() const
499 {
500         return objtype_;
501 }
502
503
504 void MathMatrixInset::setType(MathInsetTypes t)
505 {
506         objtype_ = t;
507         setDefaults();
508 }
509
510
511
512 void MathMatrixInset::mutate(MathInsetTypes newtype)
513 {
514         //lyxerr << "mutating from '" << getType() << "' to '" << newtype << "'\n";
515
516         if (newtype == getType())
517                 return;
518
519         switch (getType()) {
520                 case LM_OT_SIMPLE:
521                         setType(LM_OT_EQUATION);
522                         numbered(0, false);
523                         mutate(newtype);
524                         break;
525
526                 case LM_OT_EQUATION:
527                         switch (newtype) {
528                                 case LM_OT_SIMPLE:
529                                         setType(LM_OT_SIMPLE);
530                                         break;
531
532                                 case LM_OT_ALIGN: 
533                                 case LM_OT_ALIGNAT:
534                                 case LM_OT_XALIGNAT:
535                                 case LM_OT_XXALIGNAT: {
536
537                                         MathGridInset::addCol(1);
538
539                                         // split it "nicely"
540                                         pos_type pos = firstRelOp(cell(0));     
541                                         cell(1) = cell(0);
542                                         cell(0).erase(pos, cell(0).size());
543                                         cell(1).erase(0, pos);
544                                         setType(LM_OT_ALIGN);
545                                         mutate(newtype);
546                                         break;
547                                 }
548
549                                 case LM_OT_EQNARRAY:
550                                 default:
551                                         MathGridInset::addCol(1);
552                                         MathGridInset::addCol(1);
553
554                                         // split it "nicely" on the firest relop
555                                         pos_type pos = firstRelOp(cell(0));     
556                                         cell(1) = cell(0);
557                                         cell(0).erase(pos, cell(0).size());
558                                         cell(1).erase(0, pos);
559
560                                         if (cell(1).size()) {
561                                                 cell(2) = cell(1);
562                                                 cell(1).erase(1, cell(1).size());
563                                                 cell(2).erase(0);
564                                         }
565
566                                         setType(LM_OT_EQNARRAY);
567                                         mutate(newtype);
568                                         break;
569                                 }
570                         break;
571
572                 case LM_OT_EQNARRAY:
573                         switch (newtype) {
574                                 case LM_OT_SIMPLE:
575                                 case LM_OT_EQUATION: {
576                                         // set correct (no)numbering
577                                         bool allnonum = true;
578                                         for (row_type row = 0; row < nrows(); ++row) {
579                                                 if (!nonum_[row])
580                                                         allnonum = false;
581                                         }
582
583                                         // set first non-empty label
584                                         string label;
585                                         for (row_type row = 0; row < nrows(); ++row) {
586                                                 if (!label_[row].empty()) {
587                                                         label = label_[row];
588                                                         break;
589                                                 }
590                                         }
591
592                                         glueall();
593
594                                         nonum_[0] = allnonum;
595                                         label_[0] = label;
596                                         mutate(newtype);
597                                         break;
598                                 }
599
600                                 case LM_OT_ALIGN:
601                                 case LM_OT_ALIGNAT:
602                                 case LM_OT_XALIGNAT:
603                                 case LM_OT_XXALIGNAT:
604                                 default: {
605                                         for (row_type row = 0; row < nrows(); ++row) {
606                                                 idx_type c = 3 * row + 1;
607                                                 cell(c).push_back(cell(c + 1));
608                                         }
609                                         MathGridInset::delCol(2);
610                                         setType(LM_OT_ALIGN);
611                                         mutate(newtype);
612                                         break;
613                                 }
614                         }
615                         break;
616
617                 case LM_OT_ALIGN:
618                         switch (newtype) {
619                                 case LM_OT_SIMPLE:
620                                 case LM_OT_EQUATION:
621                                 case LM_OT_EQNARRAY:
622                                         MathGridInset::addCol(1);
623                                         setType(LM_OT_EQNARRAY);
624                                         mutate(newtype);
625                                         break;
626                                 
627                                 case LM_OT_ALIGNAT:
628                                 case LM_OT_XALIGNAT:
629                                 case LM_OT_XXALIGNAT:
630                                         setType(newtype);
631                                         break;
632
633                                 default:
634                                         lyxerr << "mutation from '" << getType()
635                                                 << "' to '" << newtype << "' not implemented\n";
636                                         break;
637                         }
638                         break;
639
640                 case LM_OT_MULTLINE:
641                         switch (newtype) {
642                                 case LM_OT_GATHER:
643                                         setType(LM_OT_GATHER);
644                                         break;
645                                 default:
646                                         lyxerr << "mutation from '" << getType()
647                                                 << "' to '" << newtype << "' not implemented\n";
648                                         break;
649                         }
650
651                 case LM_OT_GATHER:
652                         switch (newtype) {
653                                 case LM_OT_MULTLINE:
654                                         setType(LM_OT_MULTLINE);
655                                         break;
656                                 default:
657                                         lyxerr << "mutation from '" << getType()
658                                                 << "' to '" << newtype << "' not implemented\n";
659                                         break;
660                         }
661
662                 default:
663                         lyxerr << "mutation from '" << getType()
664                                 << "' to '" << newtype << "' not implemented\n";
665         }
666 }