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