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