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