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