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