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