]> git.lyx.org Git - lyx.git/blob - src/mathed/math_matrixinset.C
fix pullArg when pressing <Delete> at the end of an cell
[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 */, int, int)
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                         break;
241
242                 case LM_OT_EQUATION:
243                         if (n)
244                                 os << "\\begin{equation" << star(n) << "}\n"; 
245                         else
246                                 os << "\\[\n"; 
247                         break;
248
249                 case LM_OT_EQNARRAY:
250                         os << "\\begin{eqnarray" << star(n) << "}\n";
251                         break;
252
253                 case LM_OT_ALIGN:
254                         os << "\\begin{align" << star(n) << "}";
255                         break;
256
257                 case LM_OT_ALIGNAT:
258                         os << "\\begin{alignat" << star(n) << "}"
259                            << "{" << ncols()/2 << "}\n";
260                         break;
261                 default:
262                         os << "\\begin{unknown" << star(n) << "}";
263         }
264 }
265
266
267 void MathMatrixInset::footer_write(std::ostream & os) const
268 {
269         bool n = numberedType();
270
271         switch (GetType()) {
272                 case LM_OT_SIMPLE:
273                         os << "\\)";
274                         break;
275
276                 case LM_OT_EQUATION:
277                         if (n)
278                                 os << "\\end{equation" << star(n) << "}\n"; 
279                         else
280                                 os << "\\]\n"; 
281                         break;
282
283                 case LM_OT_EQNARRAY:
284                         os << "\\end{eqnarray" << star(n) << "}\n";
285                         break;
286
287                 case LM_OT_ALIGN:
288                         os << "\\end{align" << star(n) << "}\n";
289                         break;
290
291                 case LM_OT_ALIGNAT:
292                         os << "\\end{alignat" << star(n) << "}\n";
293                         break;
294
295                 default:
296                         os << "\\end{unknown" << star(n) << "}";
297         }
298 }
299
300
301 void MathMatrixInset::addRow(int row) 
302 {
303         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
304         label_.insert(label_.begin() + row + 1, string());
305         MathGridInset::addRow(row);
306 }
307
308 void MathMatrixInset::appendRow()
309 {
310         nonum_.push_back(!numberedType());
311         label_.push_back(string());
312         MathGridInset::appendRow();
313 }
314
315
316 void MathMatrixInset::delRow(int row) 
317 {
318         MathGridInset::delRow(row);
319         nonum_.erase(nonum_.begin() + row);
320         label_.erase(label_.begin() + row);
321 }
322
323 void MathMatrixInset::addCol(int col)
324 {
325         switch (GetType()) {
326                 case LM_OT_EQUATION:
327                         mutate(LM_OT_EQNARRAY);
328                         break;
329
330                 case LM_OT_EQNARRAY:
331                         mutate(LM_OT_ALIGN);
332                         addCol(col);
333                         break;
334
335                 case LM_OT_ALIGN:
336                 case LM_OT_ALIGNAT:
337                         MathGridInset::addCol(col);
338                         halign(col, 'l');
339                         MathGridInset::addCol(col);
340                         halign(col, 'r');
341                         break;
342
343                 default:
344                         break;
345         }
346 }
347
348 void MathMatrixInset::delCol(int col)
349 {
350         switch (GetType()) {
351                 case LM_OT_ALIGN:
352                         MathGridInset::delCol(col);
353                         break;
354
355                 default:
356                         break;
357         }
358 }
359
360
361 string MathMatrixInset::nicelabel(int row) const
362 {
363         if (nonum_[row])
364                 return string();
365         if (label_[row].empty())
366                 return string("(#)");
367         return "(" + label_[row] + ")";
368 }
369
370
371 namespace {
372         short typecode(string const & s)
373         {
374                 if (s == "equation")
375                         return LM_OT_EQUATION;
376                 if (s == "display")
377                         return LM_OT_EQUATION;
378                 if (s == "eqnarray")
379                         return LM_OT_EQNARRAY;
380                 if (s == "align")
381                         return LM_OT_ALIGN;
382                 if (s == "xalign")
383                         return LM_OT_XALIGN;
384                 if (s == "xxalign")
385                         return LM_OT_XXALIGN;
386                 if (s == "multline")
387                         return LM_OT_MULTLINE;
388                 return LM_OT_SIMPLE;
389         }       
390 }
391
392 void MathMatrixInset::mutate(string const & newtype)
393 {
394         if (newtype == "dump") {
395                 dump();
396                 return;
397         }
398         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
399         mutate(typecode(newtype));
400 }
401
402 void MathMatrixInset::glueall()
403 {
404         MathArray ar;
405         for (int i = 0; i < nargs(); ++i)
406                 ar.push_back(cell(i));
407         *this = MathMatrixInset(LM_OT_SIMPLE);
408         cell(0) = ar;
409 }
410
411 void MathMatrixInset::mutate(short newtype)
412 {
413         //lyxerr << "mutating from '" << GetType() << "' to '" << newtype << "'\n";
414
415         if (newtype == GetType())
416                 return;
417
418         switch (GetType()) {
419                 case LM_OT_SIMPLE:
420                         SetType(LM_OT_EQUATION);
421                         numbered(0, false);
422                         mutate(newtype);
423                         break;
424
425                 case LM_OT_EQUATION:
426                         switch (newtype) {
427                                 case LM_OT_SIMPLE:
428                                         SetType(LM_OT_SIMPLE);
429                                         break;
430
431                                 case LM_OT_ALIGN: {
432                                         MathGridInset::addCol(1);
433
434                                         // split it "nicely"
435                                         int pos = firstRelOp(cell(0));  
436                                         cell(1) = cell(0);
437                                         cell(0).erase(pos, cell(0).size());
438                                         cell(1).erase(0, pos);
439
440                                         halign("rl");
441                                         SetType(LM_OT_ALIGN);
442                                         break;
443                                 }
444
445                                 case LM_OT_EQNARRAY:
446                                 default:
447                                         MathGridInset::addCol(1);
448                                         MathGridInset::addCol(1);
449
450                                         // split it "nicely" on the firest relop
451                                         int pos1 = firstRelOp(cell(0)); 
452                                         cell(1) = cell(0);
453                                         cell(0).erase(pos1, cell(0).size());
454                                         cell(1).erase(0, pos1);
455                                         int pos2 = 0;
456                                         cell(1).next(pos2);
457                                         cell(2) = cell(1);
458                                         cell(1).erase(pos2, cell(1).size());
459                                         cell(2).erase(0, pos2);
460
461                                         halign("rcl");
462                                         SetType(LM_OT_EQNARRAY);
463                                         mutate(newtype);
464                                         break;
465                                 }
466                         break;
467
468                 case LM_OT_EQNARRAY:
469                         switch (newtype) {
470                                 case LM_OT_SIMPLE:
471                                 case LM_OT_EQUATION: {
472                                         // set correct (no)numbering
473                                         bool allnonum = true;
474                                         for (int r = 0; r < nrows(); ++r) {
475                                                 if (!nonum_[r])
476                                                         allnonum = false;
477                                         }
478
479                                         // set first non-empty label
480                                         string label;
481                                         for (int r = 0; r < nrows(); ++r) {
482                                                 if (!label_[r].empty()) {
483                                                         label = label_[r];
484                                                         break;
485                                                 }
486                                         }
487
488                                         glueall();
489
490                                         nonum_[0] = allnonum;
491                                         label_[0] = label;
492                                         mutate(newtype);
493                                         break;
494                                 }
495
496                                 case LM_OT_ALIGN:
497                                 default: {
498                                         for (int row = 0; row < nrows(); ++row) {
499                                                 int c = 3 * row + 1;
500                                                 cell(c).push_back(cell(c + 1));
501                                         }
502                                         MathGridInset::delCol(2);
503                                         SetType(LM_OT_ALIGN);
504                                         halign("rl");
505                                         mutate(newtype);
506                                         break;
507                                 }
508                         }
509                         break;
510
511                 case LM_OT_ALIGN:
512                         switch (newtype) {
513                                 case LM_OT_SIMPLE:
514                                 case LM_OT_EQUATION:
515                                 case LM_OT_EQNARRAY:
516                                         MathGridInset::addCol(1);
517                                         SetType(LM_OT_EQNARRAY);
518                                         halign("rcl");
519                                         mutate(newtype);
520                                         break;
521                                 
522                                 default:
523                                         lyxerr << "mutation from '" << GetType()
524                                                 << "' to '" << newtype << "' not implemented\n";
525                                         break;
526                         }
527                         break;
528
529                 default:
530                         lyxerr << "mutation from '" << GetType()
531                                 << "' to '" << newtype << "' not implemented\n";
532         }
533 }