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