]> git.lyx.org Git - features.git/blob - src/mathed/math_matrixinset.C
fix small thinko
[features.git] / src / mathed / math_matrixinset.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include <vector>
8 #include <functional>
9
10 #include "math_matrixinset.h"
11 #include "debug.h"
12 #include "support/LOstream.h"
13 #include "Painter.h"
14 #include "LaTeXFeatures.h"
15
16
17 LyXFont WhichFont(short type, int size);
18
19 namespace {
20
21 string const getAlign(short int type, int cols)
22 {
23         string align;
24         switch (type) {
25                 case LM_OT_ALIGN:
26                         for (int i = 0; i < cols; ++i)
27                                 align += "Rl";
28                         break;
29
30                 case LM_OT_ALIGNAT:
31                         for (int i = 0; i < cols; ++i)
32                                 align += "rl";
33                         break;
34
35                 case LM_OT_MULTLINE:
36                         align = "C";
37                         break;
38
39                 default:
40                         align = "rcl";
41                         break;
42         }
43         return align;
44 }
45
46
47 string const star(bool n)
48 {
49         return n ? "" : "*";
50 }
51
52
53 int getCols(short int type)
54 {
55         int col;
56         switch (type) {
57                 case LM_OT_EQNARRAY:
58                         col = 3;
59                         break;
60
61                 case LM_OT_ALIGN:
62                 case LM_OT_ALIGNAT:
63                         col = 2;
64                         break;
65
66                 default:
67                         col = 1;
68         }
69         return col;
70 }
71
72 // returns position of first relation operator in the array
73 // used for "intelligent splitting"
74 int firstRelOp(MathArray const & array)
75 {
76         for (int pos = 0; pos < array.size(); array.next(pos))
77                 if (!array.isInset(pos) &&
78                                 MathIsRelOp(array.GetChar(pos), array.GetCode(pos)))
79                         return pos;
80         return array.size();
81 }
82
83 }
84
85 MathMatrixInset::MathMatrixInset(MathInsetTypes t)
86         : MathGridInset(getCols(t), 1, "formula", t), nonum_(1), label_(1)
87 {}
88
89
90 MathMatrixInset::MathMatrixInset()
91         : MathGridInset(1, 1, "formula", LM_OT_SIMPLE), nonum_(1), label_(1)
92 {}
93
94 MathInset * MathMatrixInset::clone() const
95 {
96         return new MathMatrixInset(*this);
97 }
98
99
100 void MathMatrixInset::Metrics(MathStyles /* st */)
101 {
102         size_ = (GetType() == LM_OT_SIMPLE) ? LM_ST_TEXT : LM_ST_DISPLAY;
103
104         //LyXFont wfont = WhichFont(LM_TC_BF, size());
105         //wfont.setLatex(LyXFont::OFF);
106
107         // let the cells adjust themselves
108         MathGridInset::Metrics(size_);
109
110         if (display()) {
111                 ascent_  += 12;
112                 descent_ += 12;
113         }       
114
115         if (numberedType()) {
116                 int l = 0;
117                 for (int row = 0; row < nrows(); ++row)
118                         l = std::max(l, mathed_string_width(LM_TC_TEXTRM, size(), nicelabel(row)));
119
120                 if (l)
121                         width_ += 30 + l;
122         }
123 }
124
125
126 void MathMatrixInset::draw(Painter & pain, int x, int y)
127 {
128         xo(x);
129         yo(y);
130
131         MathGridInset::draw(pain, x, y);
132
133         if (numberedType()) {
134                 LyXFont wfont = WhichFont(LM_TC_BF, size());
135 #ifndef NO_LATEX
136                 wfont.setLatex(LyXFont::OFF);
137 #endif
138                 int xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
139                 for (int row = 0; row < nrows(); ++row) 
140                         pain.text(xx, y + rowinfo_[row].offset_, nicelabel(row), wfont);
141         }
142 }
143
144
145 void MathMatrixInset::Write(std::ostream & os, bool fragile) const
146 {
147   header_write(os);
148
149         bool n = numberedType();
150
151         for (int row = 0; row < nrows(); ++row) {
152                 if (row)
153                         os << " \\\\\n";
154                 for (int col = 0; col < ncols(); ++col) {
155                         if (col)
156                                 os << " & ";
157                         cell(index(row, col)).Write(os, fragile);
158                 }
159                 if (n) {
160                         if (!label_[row].empty())
161                                 os << "\\label{" << label_[row] << "}";
162                         if (nonum_[row])
163                                 os << "\\nonumber ";
164                 }
165         }
166
167   footer_write(os);
168 }
169
170
171 string MathMatrixInset::label(int row) const
172 {
173         return label_[row];
174 }
175
176 void MathMatrixInset::label(int row, string const & label)
177 {
178         label_[row] = label; 
179 }
180
181
182 void MathMatrixInset::numbered(int row, bool num)
183 {
184         nonum_[row] = !num; 
185 }
186
187
188 bool MathMatrixInset::numbered(int row) const
189 {
190         return !nonum_[row];
191 }
192
193
194 bool MathMatrixInset::ams() const
195 {
196         return true;
197 }
198
199
200 bool MathMatrixInset::display() const
201 {
202         return GetType() != LM_OT_SIMPLE;
203 }
204
205
206 std::vector<string> const MathMatrixInset::getLabelList() const
207 {
208         std::vector<string> res;
209         for (int row = 0; row < nrows(); ++row)
210                 if (!label_[row].empty() && nonum_[row] != 1)
211                         res.push_back(label_[row]);
212         return res;
213 }
214
215
216 bool MathMatrixInset::numberedType() const
217 {
218         if (GetType() == LM_OT_SIMPLE)
219                 return false;
220         for (int row = 0; row < nrows(); ++row)
221                 if (!nonum_[row])
222                         return true;
223         return false;
224 }
225
226
227 void MathMatrixInset::Validate(LaTeXFeatures & features)
228 {
229         features.amsstyle = ams();
230
231         // Validation is necessary only if not using AMS math.
232         // To be safe, we will always run mathedValidate.
233         //if (features.amsstyle)
234         //  return;
235
236         //Validate1(features);
237
238         features.boldsymbol = true;
239         features.binom      = true;
240 }
241
242 /*
243 void MathMatrixInset::Validate1(LaTeXFeatures & features)
244 {
245         MathIter it(cell());
246
247         while (it.OK() && !(features.binom && features.boldsymbol)) {
248                 MathInset * p = it.GetInset();
249                 if (p) {
250                         p = it.GetActiveInset();
251                         if (p) {
252                                 if (!features.binom && p->GetType() == LM_OT_MACRO &&
253                                     p->name() == "binom") {
254                                         features.binom = true;
255                                 } else {
256                                         for (int i = 0; i <= p->getMaxArgumentIdx(); ++i) {
257                                                 p->setArgumentIdx(i);
258                                                 Validate1(features, p);
259                                         }
260                                 }
261                         } else {
262                                 if (!features.boldsymbol && p->name() == "boldsymbol") 
263                                         features.boldsymbol = true;
264                         }
265                 }
266                 it.Next();
267         }
268 }
269 */
270
271
272 void MathMatrixInset::header_write(std::ostream & os) const
273 {
274         bool n = numberedType();
275
276         switch (GetType()) {
277                 case LM_OT_SIMPLE:
278                         os << "\\("; 
279                         break;
280
281                 case LM_OT_EQUATION:
282                         if (n)
283                                 os << "\\begin{equation" << star(n) << "}\n"; 
284                         else
285                                 os << "\\[\n"; 
286                         break;
287
288                 case LM_OT_EQNARRAY:
289                         os << "\\begin{eqnarray" << star(n) << "}\n";
290                         break;
291
292                 case LM_OT_ALIGN:
293                         os << "\\begin{align" << star(n) << "}";
294                         break;
295
296                 case LM_OT_ALIGNAT:
297                         os << "\\begin{alignat" << star(n) << "}"
298                            << "{" << ncols()/2 << "}\n";
299                         break;
300                 default:
301                         os << "\\begin{unknown" << star(n) << "}";
302         }
303 }
304
305
306 void MathMatrixInset::footer_write(std::ostream & os) const
307 {
308         bool n = numberedType();
309
310         switch (GetType()) {
311                 case LM_OT_SIMPLE:
312                         os << "\\)";
313                         break;
314
315                 case LM_OT_EQUATION:
316                         if (n)
317                                 os << "\\end{equation" << star(n) << "}\n"; 
318                         else
319                                 os << "\\]\n"; 
320                         break;
321
322                 case LM_OT_EQNARRAY:
323                         os << "\\end{eqnarray" << star(n) << "}\n";
324                         break;
325
326                 case LM_OT_ALIGN:
327                         os << "\\end{align" << star(n) << "}\n";
328                         break;
329
330                 case LM_OT_ALIGNAT:
331                         os << "\\end{alignat" << star(n) << "}\n";
332                         break;
333
334                 default:
335                         os << "\\end{unknown" << star(n) << "}";
336         }
337 }
338
339
340 void MathMatrixInset::addRow(int row) 
341 {
342         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
343         label_.insert(label_.begin() + row + 1, string());
344         MathGridInset::addRow(row);
345 }
346
347 void MathMatrixInset::appendRow()
348 {
349         nonum_.push_back(!numberedType());
350         label_.push_back(string());
351         MathGridInset::appendRow();
352 }
353
354
355 void MathMatrixInset::delRow(int row) 
356 {
357         MathGridInset::delRow(row);
358         nonum_.erase(nonum_.begin() + row);
359         label_.erase(label_.begin() + row);
360 }
361
362 void MathMatrixInset::addCol(int col)
363 {
364         switch (GetType()) {
365                 case LM_OT_EQUATION:
366                         mutate(LM_OT_EQNARRAY);
367                         break;
368
369                 case LM_OT_EQNARRAY:
370                         mutate(LM_OT_ALIGN);
371                         addCol(col);
372                         break;
373
374                 case LM_OT_ALIGN:
375                 case LM_OT_ALIGNAT:
376                         MathGridInset::addCol(col);
377                         halign(col, 'l');
378                         MathGridInset::addCol(col);
379                         halign(col, 'r');
380                         break;
381
382                 default:
383                         break;
384         }
385 }
386
387 void MathMatrixInset::delCol(int col)
388 {
389         switch (GetType()) {
390                 case LM_OT_ALIGN:
391                         MathGridInset::delCol(col);
392                         break;
393
394                 default:
395                         break;
396         }
397 }
398
399
400 string MathMatrixInset::nicelabel(int row) const
401 {
402         if (nonum_[row])
403                 return string();
404         if (label_[row].empty())
405                 return string("(#)");
406         return "(" + label_[row] + ")";
407 }
408
409
410 namespace {
411         short typecode(string const & s)
412         {
413                 if (s == "equation")
414                         return LM_OT_EQUATION;
415                 if (s == "display")
416                         return LM_OT_EQUATION;
417                 if (s == "eqnarray")
418                         return LM_OT_EQNARRAY;
419                 if (s == "align")
420                         return LM_OT_ALIGN;
421                 if (s == "xalign")
422                         return LM_OT_XALIGN;
423                 if (s == "xxalign")
424                         return LM_OT_XXALIGN;
425                 if (s == "multline")
426                         return LM_OT_MULTLINE;
427                 return LM_OT_SIMPLE;
428         }       
429 }
430
431 void MathMatrixInset::mutate(string const & newtype)
432 {
433         if (newtype == "dump") {
434                 dump();
435                 return;
436         }
437         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
438         mutate(typecode(newtype));
439 }
440
441 void MathMatrixInset::glueall()
442 {
443         MathArray ar;
444         for (int i = 0; i < nargs(); ++i)
445                 ar.push_back(cell(i));
446         *this = MathMatrixInset(LM_OT_SIMPLE);
447         cell(0) = ar;
448 }
449
450 void MathMatrixInset::mutate(short newtype)
451 {
452         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
453
454         if (newtype == GetType())
455                 return;
456
457         switch (GetType()) {
458                 case LM_OT_SIMPLE:
459                         SetType(LM_OT_EQUATION);
460                         numbered(false);
461                         mutate(newtype);
462                         break;
463
464                 case LM_OT_EQUATION:
465                         switch (newtype) {
466                                 case LM_OT_SIMPLE:
467                                         SetType(LM_OT_SIMPLE);
468                                         break;
469
470                                 case LM_OT_ALIGN: {
471                                         MathGridInset::addCol(1);
472
473                                         // split it "nicely"
474                                         int pos = firstRelOp(cell(0));  
475                                         cell(1) = cell(0);
476                                         cell(0).erase(pos, cell(0).size());
477                                         cell(1).erase(0, pos);
478
479                                         halign("rl");
480                                         SetType(LM_OT_ALIGN);
481                                         break;
482                                 }
483
484                                 case LM_OT_EQNARRAY:
485                                 default:
486                                         MathGridInset::addCol(1);
487                                         MathGridInset::addCol(1);
488
489                                         // split it "nicely" on the firest relop
490                                         int pos1 = firstRelOp(cell(0)); 
491                                         cell(1) = cell(0);
492                                         cell(0).erase(pos1, cell(0).size());
493                                         cell(1).erase(0, pos1);
494                                         int pos2 = 0;
495                                         cell(1).next(pos2);
496                                         cell(2) = cell(1);
497                                         cell(1).erase(pos2, cell(1).size());
498                                         cell(2).erase(0, pos2);
499
500                                         halign("rcl");
501                                         SetType(LM_OT_EQNARRAY);
502                                         mutate(newtype);
503                                         break;
504                                 }
505                         break;
506
507                 case LM_OT_EQNARRAY:
508                         switch (newtype) {
509                                 case LM_OT_SIMPLE:
510                                 case LM_OT_EQUATION: {
511                                         // set correct (no)numbering
512                                         bool allnonum = true;
513                                         for (int r = 0; r < nrows(); ++r) {
514                                                 if (!nonum_[r])
515                                                         allnonum = false;
516                                         }
517
518                                         // set first non-empty label
519                                         string label;
520                                         for (int r = 0; r < nrows(); ++r) {
521                                                 if (!label_[r].empty()) {
522                                                         label = label_[r];
523                                                         break;
524                                                 }
525                                         }
526
527                                         glueall();
528
529                                         nonum_[0] = allnonum;
530                                         label_[0] = label;
531                                         mutate(newtype);
532                                         break;
533                                 }
534
535                                 case LM_OT_ALIGN:
536                                 default: {
537                                         for (int row = 0; row < nrows(); ++row) {
538                                                 int c = 3 * row + 1;
539                                                 cell(c).push_back(cell(c + 1));
540                                         }
541                                         MathGridInset::delCol(2);
542                                         SetType(LM_OT_ALIGN);
543                                         halign("rl");
544                                         mutate(newtype);
545                                         break;
546                                 }
547                         }
548                         break;
549
550                 case LM_OT_ALIGN:
551                         switch (newtype) {
552                                 case LM_OT_SIMPLE:
553                                 case LM_OT_EQUATION:
554                                 case LM_OT_EQNARRAY:
555                                         MathGridInset::addCol(1);
556                                         SetType(LM_OT_EQNARRAY);
557                                         halign("rcl");
558                                         mutate(newtype);
559                                         break;
560                                 
561                                 default:
562                                         lyxerr << "mutation from '" << GetType()
563                                                 << "' to '" << newtype << "' not implemented\n";
564                                         break;
565                         }
566                         break;
567
568                 default:
569                         lyxerr << "mutation from '" << GetType()
570                                 << "' to '" << newtype << "' not implemented\n";
571         }
572 }