]> git.lyx.org Git - lyx.git/blob - src/mathed/math_scriptinset.C
architectural changes to tex2lyx
[lyx.git] / src / mathed / math_scriptinset.C
1 #include <config.h>
2
3 #include "math_scriptinset.h"
4 #include "math_support.h"
5 #include "math_symbolinset.h"
6 #include "math_mathmlstream.h"
7 #include "funcrequest.h"
8 #include "support/LAssert.h"
9 #include "debug.h"
10
11 using namespace lyx::support;
12
13 using std::max;
14 using std::auto_ptr;
15 using std::endl;
16
17
18 MathScriptInset::MathScriptInset()
19         : MathNestInset(3), limits_(0)
20 {
21         script_[0] = false;
22         script_[1] = false;
23 }
24
25
26 MathScriptInset::MathScriptInset(bool up)
27         : MathNestInset(3), limits_(0)
28 {
29         script_[0] = !up;
30         script_[1] = up;
31 }
32
33
34 MathScriptInset::MathScriptInset(MathAtom const & at, bool up)
35         : MathNestInset(3), limits_(0)
36 {
37         script_[0] = !up;
38         script_[1] = up;
39         cell(2).push_back(at);
40 }
41
42
43
44 auto_ptr<InsetBase> MathScriptInset::clone() const
45 {
46         return auto_ptr<InsetBase>(new MathScriptInset(*this));
47 }
48
49
50 MathScriptInset const * MathScriptInset::asScriptInset() const
51 {
52         return this;
53 }
54
55
56 MathScriptInset * MathScriptInset::asScriptInset()
57 {
58         return this;
59 }
60
61
62 bool MathScriptInset::idxFirst(idx_type & idx, pos_type & pos) const
63 {
64         idx = 2;
65         pos = 0;
66         return true;
67 }
68
69
70 bool MathScriptInset::idxLast(idx_type & idx, pos_type & pos) const
71 {
72         idx = 2;
73         pos = nuc().size();
74         return true;
75 }
76
77
78 MathArray const & MathScriptInset::down() const
79 {
80         return cell(0);
81 }
82
83
84 MathArray & MathScriptInset::down()
85 {
86         return cell(0);
87 }
88
89
90 MathArray const & MathScriptInset::up() const
91 {
92         return cell(1);
93 }
94
95
96 MathArray & MathScriptInset::up()
97 {
98         return cell(1);
99 }
100
101
102 void MathScriptInset::ensure(bool up)
103 {
104         script_[up] = true;
105 }
106
107
108 MathArray const & MathScriptInset::nuc() const
109 {
110         return cell(2);
111 }
112
113
114 MathArray & MathScriptInset::nuc()
115 {
116         return cell(2);
117 }
118
119
120 int MathScriptInset::dy0() const
121 {
122         int nd = ndes();
123         if (!hasDown())
124                 return nd;
125         int des = down().ascent();
126         if (hasLimits())
127                 des += nd + 2;
128         else
129                 des = max(des, nd);
130         return des;
131 }
132
133
134 int MathScriptInset::dy1() const
135 {
136         int na = nasc();
137         if (!hasUp())
138                 return na;
139         int asc = up().descent();
140         if (hasLimits())
141                 asc += na + 2;
142         else
143                 asc = max(asc, na);
144         asc = max(asc, 5);
145         return asc;
146 }
147
148
149 int MathScriptInset::dx0() const
150 {
151         Assert(hasDown());
152         return hasLimits() ? (dim_.wid - down().width()) / 2 : nwid();
153 }
154
155
156 int MathScriptInset::dx1() const
157 {
158         Assert(hasUp());
159         return hasLimits() ? (dim_.wid - up().width()) / 2 : nwid();
160 }
161
162
163 int MathScriptInset::dxx() const
164 {
165         return hasLimits() ? (dim_.wid - nwid()) / 2  :  0;
166 }
167
168
169 int MathScriptInset::nwid() const
170 {
171         return nuc().size() ? nuc().width() : 2;
172 }
173
174
175 int MathScriptInset::nasc() const
176 {
177         return nuc().size() ? nuc().ascent() : 5;
178 }
179
180
181 int MathScriptInset::ndes() const
182 {
183         return nuc().size() ? nuc().descent() : 0;
184 }
185
186
187 void MathScriptInset::metrics(MetricsInfo & mi, Dimension & dim) const
188 {
189         cell(2).metrics(mi);
190         ScriptChanger dummy(mi.base);
191         cell(0).metrics(mi);
192         cell(1).metrics(mi);
193         dim_.wid = 0;
194         if (hasLimits()) {
195                 dim_.wid = nwid();
196                 if (hasUp())
197                         dim_.wid = max(dim_.wid, up().width());
198                 if (hasDown())
199                         dim_.wid = max(dim_.wid, down().width());
200         } else {
201                 if (hasUp())
202                         dim_.wid = max(dim_.wid, up().width());
203                 if (hasDown())
204                         dim_.wid = max(dim_.wid, down().width());
205                 dim_.wid += nwid();
206         }
207         dim_.asc = dy1() + (hasUp() ? up().ascent() : 0);
208         dim_.des = dy0() + (hasDown() ? down().descent() : 0);
209         metricsMarkers();
210         dim = dim_;
211 }
212
213
214 void MathScriptInset::draw(PainterInfo & pi, int x, int y) const
215 {
216         if (nuc().size())
217                 nuc().draw(pi, x + dxx(), y);
218         else {
219                 nuc().setXY(x + dxx(), y);
220                 if (editing())
221                         drawStr(pi, pi.base.font, x + dxx(), y, ".");
222         }
223         ScriptChanger dummy(pi.base);
224         if (hasUp())
225                 up().draw(pi, x + dx1(), y - dy1());
226         if (hasDown())
227                 down().draw(pi, x + dx0(), y + dy0());
228         drawMarkers(pi, x, y);
229 }
230
231
232 void MathScriptInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
233 {
234         if (hasUp())
235                 up().metricsT(mi, dim);
236         if (hasDown())
237                 down().metricsT(mi, dim);
238         nuc().metricsT(mi, dim);
239 }
240
241
242 void MathScriptInset::drawT(TextPainter & pain, int x, int y) const
243 {
244         if (nuc().size())
245                 nuc().drawT(pain, x + dxx(), y);
246         if (hasUp())
247                 up().drawT(pain, x + dx1(), y - dy1());
248         if (hasDown())
249                 down().drawT(pain, x + dx0(), y + dy0());
250 }
251
252
253
254 bool MathScriptInset::hasLimits() const
255 {
256         // obvious cases
257         if (limits_ == 1)
258                 return true;
259         if (limits_ == -1)
260                 return false;
261
262         // we can only display limits if the nucleus wants some
263         if (!nuc().size())
264                 return false;
265         if (!nuc().back()->isScriptable())
266                 return false;
267
268         // per default \int has limits beside the \int even in displayed formulas
269         if (nuc().back()->asSymbolInset())
270                 if (nuc().back()->asSymbolInset()->name().find("int") != string::npos)
271                         return false;
272
273         // assume "real" limits for everything else
274         return true;
275 }
276
277
278 void MathScriptInset::removeScript(bool up)
279 {
280         cell(up).clear();
281         script_[up] = false;
282 }
283
284
285 bool MathScriptInset::has(bool up) const
286 {
287         return script_[up];
288 }
289
290
291 bool MathScriptInset::hasUp() const
292 {
293         return script_[1];
294 }
295
296
297 bool MathScriptInset::hasDown() const
298 {
299         return script_[0];
300 }
301
302
303 bool MathScriptInset::idxRight(idx_type &, pos_type &) const
304 {
305         return false;
306 }
307
308
309 bool MathScriptInset::idxLeft(idx_type &, pos_type &) const
310 {
311         return false;
312 }
313
314
315 bool MathScriptInset::idxUpDown(idx_type & idx, pos_type & pos, bool up,
316         int) const
317 {
318         if (idx == 1) {
319                 // if we are 'up' we can't go further up
320                 if (up)
321                         return false;
322                 // otherwise go to last base position
323                 idx = 2;
324                 pos = cell(2).size();
325         }
326
327         else if (idx == 0) {
328                 // if we are 'down' we can't go further down
329                 if (!up)
330                         return false;
331                 idx = 2;
332                 pos = cell(2).size();
333         }
334
335         else {
336                 // in nucleus
337                 // don't go up/down if there is no cell.
338                 if (!has(up))
339                         return false;
340                 // go up/down only if in the last position
341                 // or in the first position of something with displayed limits
342                 if (pos == cell(2).size() || (pos == 0 && hasLimits())) {
343                         idx = up;
344                         pos = 0;
345                         return true;
346                 }
347                 return false;
348         }
349         return true;
350 }
351
352
353 void MathScriptInset::write(WriteStream & os) const
354 {
355         if (nuc().size()) {
356                 os << nuc();
357                 //if (nuc().back()->takesLimits()) {
358                         if (limits_ == -1)
359                                 os << "\\nolimits ";
360                         if (limits_ == 1)
361                                 os << "\\limits ";
362                 //}
363         } else {
364                 if (os.firstitem())
365                         lyxerr[Debug::MATHED] << "suppressing {} when writing"
366                                               << endl;
367                 else
368                         os << "{}";
369         }
370
371         if (hasDown() && down().size())
372                 os << "_{" << down() << '}';
373
374         if (hasUp() && up().size())
375                 os << "^{" << up() << '}';
376
377         if (lock_ && !os.latex())
378                 os << "\\lyxlock ";
379 }
380
381
382 void MathScriptInset::normalize(NormalStream & os) const
383 {
384         bool d = hasDown() && down().size();
385         bool u = hasUp() && up().size();
386
387         if (u && d)
388                 os << "[subsup ";
389         else if (u)
390                 os << "[sup ";
391         else if (d)
392                 os << "[sub ";
393
394         if (nuc().size())
395                 os << nuc() << ' ';
396         else
397                 os << "[par]";
398
399         if (u && d)
400                 os << down() << ' ' << up() << ']';
401         else if (d)
402                 os << down() << ']';
403         else if (u)
404                 os << up() << ']';
405 }
406
407
408 void MathScriptInset::maple(MapleStream & os) const
409 {
410         if (nuc().size())
411                 os << nuc();
412         if (hasDown() && down().size())
413                 os << '[' << down() << ']';
414         if (hasUp() && up().size())
415                 os << "^(" << up() << ')';
416 }
417
418
419 void MathScriptInset::mathematica(MathematicaStream & os) const
420 {
421         bool d = hasDown() && down().size();
422         bool u = hasUp() && up().size();
423
424         if (nuc().size()) {
425                 if (d)
426                         os << "Subscript[" << nuc();
427                 else
428                         os << nuc();
429         }
430
431         if (u)
432                 os << "^(" << up() << ')';
433
434         if (nuc().size())
435                 if (d)
436                         os << ',' << down() << ']';
437 }
438
439
440 void MathScriptInset::mathmlize( MathMLStream & os) const
441 {
442         bool d = hasDown() && down().size();
443         bool u = hasUp() && up().size();
444
445         if (u && d)
446                 os << MTag("msubsup");
447         else if (u)
448                 os << MTag("msup");
449         else if (d)
450                 os << MTag("msub");
451
452         if (nuc().size())
453                 os << nuc();
454         else
455                 os << "<mrow/>";
456
457         if (u && d)
458                 os << down() << up() << ETag("msubsup");
459         else if (u)
460                 os << up() << ETag("msup");
461         else if (d)
462                 os << down() << ETag("msub");
463 }
464
465
466 void MathScriptInset::octave(OctaveStream & os) const
467 {
468         if (nuc().size())
469                 os << nuc();
470         if (hasDown() && down().size())
471                 os << '[' << down() << ']';
472         if (hasUp() && up().size())
473                 os << "^(" << up() << ')';
474 }
475
476
477 void MathScriptInset::infoize(std::ostream & os) const
478 {
479         os << "Scripts";
480 }
481
482
483 void MathScriptInset::infoize2(std::ostream & os) const
484 {
485         if (limits_)
486                 os << (limits_ == 1 ? ", Displayed limits" : ", Inlined limits");
487 }
488
489
490 void MathScriptInset::notifyCursorLeaves(idx_type idx)
491 {
492         MathNestInset::notifyCursorLeaves(idx);
493
494         // remove empty scripts if possible
495         if (idx != 2 && script_[idx] && cell(idx).empty()) {
496                 cell(idx).clear();
497                 script_[idx] = false;
498         }
499 }
500
501
502 dispatch_result MathScriptInset::dispatch
503         (FuncRequest const & cmd, idx_type & idx, pos_type & pos)
504 {
505         if (cmd.action == LFUN_MATH_LIMITS) {
506                 if (!cmd.argument.empty()) {
507                         if (cmd.argument == "limits")
508                                 limits_ = 1;
509                         else if (cmd.argument == "nolimits")
510                                 limits_ = -1;
511                         else
512                                 limits_ = 0;
513                 } else if (limits_ == 0)
514                         limits_ =  (hasLimits()) ? -1 : 1;
515                 else
516                         limits_ = 0;
517                 return DISPATCHED;
518         }
519
520         return MathNestInset::dispatch(cmd, idx, pos);
521 }