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