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