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