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