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