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