]> git.lyx.org Git - lyx.git/blob - src/mathed/math_scriptinset.C
fix drawing glitch with \int (limits are on the side per default even in
[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 "support/LAssert.h"
10 #include "debug.h"
11
12
13 MathScriptInset::MathScriptInset()
14         : MathNestInset(2), limits_(0)
15 {
16         script_[0] = false;
17         script_[1] = false;
18 }
19
20
21 MathScriptInset::MathScriptInset(bool up)
22         : MathNestInset(2), limits_(0)
23 {
24         script_[0] = !up;
25         script_[1] = up;
26 }
27
28
29 MathInset * MathScriptInset::clone() const
30 {
31         return new MathScriptInset(*this);
32 }
33
34
35 MathScriptInset const * MathScriptInset::asScriptInset() const
36 {
37         return this;
38 }
39
40
41 MathScriptInset * MathScriptInset::asScriptInset()
42 {
43         return this;
44 }
45
46
47 MathXArray const & MathScriptInset::up() const
48 {
49         return xcell(1);
50 }
51
52
53 MathXArray const & MathScriptInset::down() const
54 {
55         return xcell(0);
56 }
57
58
59 MathXArray & MathScriptInset::up()
60 {
61         return xcell(1);
62 }
63
64
65 MathXArray & MathScriptInset::down()
66 {
67         return xcell(0);
68 }
69
70
71 void MathScriptInset::ensure(bool up)
72 {
73         script_[up] = true;
74 }
75
76
77 bool MathScriptInset::covers(int x, int y) const
78 {
79         for (idx_type i = 0; i < 2; ++i)
80                 if (has(i) && xcell(i).covers(x, y))
81                         return true;
82         return false;
83 }
84
85
86 int MathScriptInset::dy0(MathInset const * nuc) const
87 {
88         int nd = ndes(nuc);
89         if (!hasDown())
90                 return nd;
91         int des = down().ascent();
92         if (hasLimits(nuc))
93                 des += nd + 2;
94         else 
95                 des = std::max(des, nd);
96         return des;
97 }
98
99
100 int MathScriptInset::dy1(MathInset const * nuc) const
101 {
102         int na = nasc(nuc);
103         if (!hasUp())
104                 return na;
105         int asc = up().descent();
106         if (hasLimits(nuc))
107                 asc += na + 2;
108         else 
109                 asc = std::max(asc, na);
110         asc = std::max(asc, mathed_char_ascent(LM_TC_VAR, mi_, 'I'));
111         return asc;
112 }
113
114
115 int MathScriptInset::dx0(MathInset const * nuc) const
116 {
117         lyx::Assert(hasDown());
118         return hasLimits(nuc) ? (width(nuc) - down().width()) / 2 : nwid(nuc);
119 }
120
121
122 int MathScriptInset::dx1(MathInset const * nuc) const
123 {
124         lyx::Assert(hasUp());
125         return hasLimits(nuc) ? (width(nuc) - up().width()) / 2 : nwid(nuc);
126 }
127
128
129 int MathScriptInset::dxx(MathInset const * nuc) const
130 {
131         //lyx::Assert(nuc());
132         return hasLimits(nuc)  ?  (width(nuc) - nwid(nuc)) / 2  :  0;
133 }
134
135
136 int MathScriptInset::ascent(MathInset const * nuc) const
137 {
138         return dy1(nuc) + (hasUp() ? up().ascent() : 0);
139 }
140
141
142 int MathScriptInset::descent(MathInset const * nuc) const
143 {
144         return dy0(nuc) + (hasDown() ? down().descent() : 0);
145 }
146
147
148 int MathScriptInset::width(MathInset const * nuc) const
149 {
150         int wid = 0;
151         if (hasLimits(nuc)) {
152                 wid = nwid(nuc);
153                 if (hasUp())
154                         wid = std::max(wid, up().width());
155                 if (hasDown())
156                         wid = std::max(wid, down().width());
157         } else {
158                 if (hasUp())
159                         wid = std::max(wid, up().width());
160                 if (hasDown())
161                         wid = std::max(wid, down().width());
162                 wid += nwid(nuc);
163         }
164         return wid;
165 }
166
167
168 int MathScriptInset::nwid(MathInset const * nuc) const
169 {
170         return nuc ?
171                 nuc->width() :
172                 mathed_char_width(LM_TC_TEX, mi_, '.');
173 }
174
175
176 int MathScriptInset::nasc(MathInset const * nuc) const
177 {
178         return nuc ? nuc->ascent()
179                 : mathed_char_ascent(LM_TC_VAR, mi_, 'I');
180 }
181
182
183 int MathScriptInset::ndes(MathInset const * nuc) const
184 {
185         return nuc ? nuc->descent()
186                 : mathed_char_descent(LM_TC_VAR, mi_, 'I');
187 }
188
189
190 void MathScriptInset::metrics(MathMetricsInfo const & mi) const
191 {       
192         metrics(0, mi);
193 }
194
195
196 void MathScriptInset::metrics(MathInset const * nuc,
197         MathMetricsInfo const & mi) const
198 {       
199         MathNestInset::metrics(mi);
200         if (nuc)
201                 nuc->metrics(mi);
202
203         ascent_  = ascent(nuc);
204         descent_ = descent(nuc);
205         width_   = width(nuc);
206 }
207
208
209 void MathScriptInset::draw(Painter & pain, int x, int y) const
210 {  
211         //lyxerr << "unexpected call to MathScriptInset::draw()\n";
212         draw(0, pain, x, y);
213 }
214
215
216 void MathScriptInset::draw(MathInset const * nuc, Painter & pain,
217         int x, int y) const
218 {  
219         if (nuc)
220                 nuc->draw(pain, x + dxx(nuc), y);
221         else
222                 drawStr(pain, LM_TC_TEX, mi_, x + dxx(nuc), y, ".");
223
224         if (hasUp())
225                 up().draw(pain, x + dx1(nuc), y - dy1(nuc));
226
227         if (hasDown())
228                 down().draw(pain, x + dx0(nuc), y + dy0(nuc));
229 }
230
231
232 bool MathScriptInset::hasLimits(MathInset const * nuc) const
233 {
234         // obviuos cases
235         if (limits_ == 1)
236                 return true;
237         if (limits_ == -1)
238                 return false;
239
240         // we can only display limits if the nucleus wants some 
241         if (!nuc)
242                 return false;
243         if (!nuc->isScriptable())
244                 return false;
245         
246         // per default \int has limits beside the \int even in displayed formulas
247         if (nuc->asSymbolInset())
248                 if (nuc->asSymbolInset()->name().find("int") != string::npos)
249                         return false;
250
251         // assume "real" limits for everything else
252         return true;
253 }
254
255
256 void MathScriptInset::removeEmptyScripts()
257 {
258         for (int i = 0; i <= 1; ++i)
259                 if (script_[i] && !cell(i).size())
260                         script_[i] = false;
261 }
262
263
264 void MathScriptInset::removeScript(bool up)
265 {
266         cell(up).clear();
267         script_[up] = false;
268 }
269
270
271 bool MathScriptInset::has(bool up) const
272 {
273         return script_[up];
274 }
275
276
277 bool MathScriptInset::hasUp() const
278 {
279         return script_[1];
280 }
281
282
283 bool MathScriptInset::hasDown() const
284 {
285         return script_[0];
286 }
287
288
289 bool MathScriptInset::idxRight(MathInset::idx_type &,
290                                  MathInset::pos_type &) const
291 {
292         return false;
293 }
294
295
296 bool MathScriptInset::idxLeft(MathInset::idx_type &,
297                                 MathInset::pos_type &) const
298 {
299         return false;
300 }
301
302
303 bool MathScriptInset::idxFirstUp(idx_type & idx, pos_type & pos) const
304 {
305         if (!hasUp())
306                 return false;
307         idx = 1;
308         pos = 0; 
309         return true;
310 }
311
312
313 bool MathScriptInset::idxFirstDown(idx_type & idx, pos_type & pos) const
314 {
315         if (!hasDown())
316                 return false;
317         idx = 0;
318         pos = 0; 
319         return true;
320 }
321
322
323 bool MathScriptInset::idxLastUp(idx_type & idx, pos_type & pos) const
324 {
325         if (!hasUp())
326                 return false;
327         idx = 1;
328         pos = up().data_.size(); 
329         return true;
330 }
331
332
333 bool MathScriptInset::idxLastDown(idx_type & idx, pos_type & pos) const
334 {
335         if (!hasDown())
336                 return false;
337         idx = 0;
338         pos = down().data_.size(); 
339         return true;
340 }
341
342
343 void MathScriptInset::write(WriteStream & os) const
344 {  
345         //lyxerr << "unexpected call to MathScriptInset::write()\n";
346         write2(0, os);
347 }
348
349
350 void MathScriptInset::write2(MathInset const * nuc, WriteStream & os) const
351 {
352         if (nuc) {
353                 os << nuc;
354                 if (nuc->takesLimits()) {
355                         if (limits_ == -1)
356                                 os << "\\nolimits ";
357                         if (limits_ == 1)
358                                 os << "\\limits ";
359                 }
360         } else
361                         if (os.firstitem)
362                                 lyxerr << "suppressing {} \n";
363                         else
364                                 os << "{}";
365
366         if (hasDown() && down().data_.size())
367                 os << "_{" << down().data_ << '}';
368
369         if (hasUp() && up().data_.size())
370                 os << "^{" << up().data_ << '}';
371 }
372
373
374 void MathScriptInset::normalize(NormalStream & os) const
375 {  
376         //lyxerr << "unexpected call to MathScriptInset::normalize()\n";
377         normalize2(0, os);
378 }
379
380
381 void MathScriptInset::normalize2(MathInset const * nuc, NormalStream & os) const
382 {
383         bool d = hasDown() && down().data_.size();
384         bool u = hasUp() && up().data_.size();
385
386         if (u) 
387                 os << "[sup ";
388         if (d)
389                 os << "[sub ";
390         
391         if (nuc)
392                 os << nuc << ' ';
393         else
394                 os << "[par]";
395
396         if (d)
397                 os << down().data_ << ']';
398         if (u) 
399                 os << up().data_ << ']';
400 }
401
402
403 void MathScriptInset::maplize2(MathInset const * nuc, MapleStream & os) const
404 {
405         if (nuc)
406                 os << nuc;
407         if (hasDown() && down().data_.size())
408                 os << '[' << down().data_ << ']';
409         if (hasUp() && up().data_.size())
410                 os << "^(" << up().data_ << ')';
411 }
412
413
414 void MathScriptInset::mathmlize2(MathInset const * nuc, MathMLStream & os) const
415 {
416         bool d = hasDown() && down().data_.size();
417         bool u = hasUp() && up().data_.size();
418
419         if (u && d)
420                 os << MTag("msubsup");
421         else if (u)
422                 os << MTag("msup");
423         else if (d)
424                 os << MTag("msub");
425
426         if (nuc)
427                 os << nuc;
428         else
429                 os << "<mrow/>";
430
431         if (u && d)
432                 os << down().data_ << up().data_ << ETag("msubsup");
433         else if (u)
434                 os << up().data_ << ETag("msup");
435         else if (d)
436                 os << down().data_ << ETag("msub");
437 }
438
439
440 void MathScriptInset::octavize2(MathInset const * nuc, OctaveStream & os) const
441 {
442         if (nuc)
443                 os << nuc;
444         if (hasDown() && down().data_.size())
445                 os << '[' << down().data_ << ']';
446         if (hasUp() && up().data_.size())
447                 os << "^(" << up().data_ << ')';
448 }
449
450