]> git.lyx.org Git - lyx.git/blob - src/mathed/math_data.C
small up/down tweaking
[lyx.git] / src / mathed / math_data.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "math_data.h"
8 #include "math_inset.h"
9 #include "math_cursor.h"
10 #include "math_deliminset.h"
11 #include "math_fontinset.h"
12 #include "math_scriptinset.h"
13 #include "math_mathmlstream.h"
14 #include "math_support.h"
15 #include "math_replace.h"
16 #include "debug.h"
17 #include "support/LAssert.h"
18 #include "math_metricsinfo.h"
19 #include "frontends/Painter.h"
20 #include "textpainter.h"
21
22
23 using std::max;
24 using std::min;
25 using std::abs;
26
27
28
29 MathArray::MathArray()
30         : xo_(0), yo_(0), clean_(false), drawn_(false)
31 {}
32
33
34 MathArray::MathArray(const_iterator from, const_iterator to)
35         : base_type(from, to), xo_(0), yo_(0), clean_(false), drawn_(false)
36 {}
37
38
39 void MathArray::substitute(MathMacro const & m)
40 {
41         for (iterator it = begin(); it != end(); ++it)
42                 it->nucleus()->substitute(m);
43 }
44
45
46 MathAtom & MathArray::operator[](size_type pos)
47 {
48         lyx::Assert(pos < size());
49         return base_type::operator[](pos);
50 }
51
52
53 MathAtom const & MathArray::operator[](size_type pos) const
54 {
55         lyx::Assert(pos < size());
56         return base_type::operator[](pos);
57 }
58
59
60 void MathArray::insert(size_type pos, MathAtom const & t)
61 {
62         base_type::insert(begin() + pos, t);
63 }
64
65
66 void MathArray::insert(size_type pos, MathArray const & ar)
67 {
68         lyx::Assert(pos <= size());
69         base_type::insert(begin() + pos, ar.begin(), ar.end());
70 }
71
72
73 void MathArray::append(MathArray const & ar)
74 {
75         insert(size(), ar);
76 }
77
78
79 void MathArray::erase(size_type pos)
80 {
81         if (pos < size())
82                 erase(pos, pos + 1);
83 }
84
85
86 void MathArray::erase(iterator pos1, iterator pos2)
87 {
88         base_type::erase(pos1, pos2);
89 }
90
91
92 void MathArray::erase(iterator pos)
93 {
94         base_type::erase(pos);
95 }
96
97
98 void MathArray::erase(size_type pos1, size_type pos2)
99 {
100         base_type::erase(begin() + pos1, begin() + pos2);
101 }
102
103
104 void MathArray::dump2() const
105 {
106         NormalStream ns(lyxerr);
107         for (const_iterator it = begin(); it != end(); ++it)
108                 ns << *it << ' ';
109 }
110
111
112 void MathArray::dump() const
113 {
114         NormalStream ns(lyxerr);
115         for (const_iterator it = begin(); it != end(); ++it)
116                 ns << '<' << *it << '>';
117 }
118
119
120 void MathArray::validate(LaTeXFeatures & features) const
121 {
122         for (const_iterator it = begin(); it != end(); ++it)
123                 (*it)->validate(features);
124 }
125
126
127 bool MathArray::match(MathArray const & ar) const
128 {
129         return size() == ar.size() && matchpart(ar, 0);
130 }
131
132
133 bool MathArray::matchpart(MathArray const & ar, pos_type pos) const
134 {
135         if (size() < ar.size() + pos)
136                 return false;
137         const_iterator it = begin() + pos;
138         for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it)
139                 if (!(*jt)->match(*it))
140                         return false;
141         return true;
142 }
143
144
145 void MathArray::replace(ReplaceData & rep)
146 {
147         for (size_type i = 0; i < size(); ++i) {
148                 if (find1(rep.from, i)) {
149                         // match found
150                         lyxerr << "match found!\n";
151                         erase(i, i + rep.from.size());
152                         insert(i, rep.to);
153                 }
154         }
155
156 #ifdef WITH_WARNINGS
157 #warning temporarily disabled
158         // for (const_iterator it = begin(); it != end(); ++it)
159         //      it->nucleus()->replace(rep);
160 #endif
161 }
162
163
164 bool MathArray::find1(MathArray const & ar, size_type pos) const
165 {
166         //lyxerr << "finding '" << ar << "' in '" << *this << "'\n";
167         for (size_type i = 0, n = ar.size(); i < n; ++i)
168                 if (!operator[](pos + i)->match(ar[i]))
169                         return false;
170         return true;
171 }
172
173
174 MathArray::size_type MathArray::find(MathArray const & ar) const
175 {
176         for (int i = 0, last = size() - ar.size(); i < last; ++i)
177                 if (find1(ar, i))
178                         return i;
179         return size();
180 }
181
182
183 MathArray::size_type MathArray::find_last(MathArray const & ar) const
184 {
185         for (int i = size() - ar.size(); i >= 0; --i)
186                 if (find1(ar, i))
187                         return i;
188         return size();
189 }
190
191
192 bool MathArray::contains(MathArray const & ar) const
193 {
194         if (find(ar) != size())
195                 return true;
196         for (const_iterator it = begin(); it != end(); ++it)
197                 if ((*it)->contains(ar))
198                         return true;
199         return false;
200 }
201
202
203 void MathArray::touch() const
204 {
205         clean_  = false;
206         drawn_  = false;
207 }
208
209
210 Dimension const & MathArray::metrics(MathMetricsInfo & mi) const
211 {
212         //if (clean_)
213         //      return;
214         clean_  = true;
215         drawn_  = false;
216
217         mathed_char_dim(mi.base.font, 'I', dim_);
218         if (empty())
219                 return dim_;
220
221         dim_.w = 0;
222         for (const_iterator it = begin(), et = end(); it != et; ++it) {
223                 (*it)->metrics(mi);
224                 dim_ += (*it)->dimensions();
225         }
226         return dim_;
227 }
228
229
230 void MathArray::draw(MathPainterInfo & pi, int x, int y) const
231 {
232         //if (drawn_ && x == xo_ && y == yo_)
233         //      return;
234         //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl;
235
236         xo_    = x;
237         yo_    = y;
238         drawn_ = true;
239
240         if (y + descent() <= 0)                   // don't draw above the workarea
241                 return;
242         if (y - ascent() >= pi.pain.paperHeight())   // don't draw below the workarea
243                 return;
244         if (x + width() <= 0)                     // don't draw left of workarea
245                 return;
246         if (x >= pi.pain.paperWidth())              // don't draw right of workarea
247                 return;
248
249         if (empty()) {
250                 pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline);
251                 return;
252         }
253
254         for (const_iterator it = begin(), et = end(); it != et; ++it) {
255                 (*it)->draw(pi, x, y);
256                 x += (*it)->width();
257         }
258 }
259
260
261 Dimension const & MathArray::metricsT(TextMetricsInfo const & mi) const
262 {
263         //if (clean_)
264         //      return;
265         dim_.clear();
266         for (const_iterator it = begin(); it != end(); ++it) {
267                 (*it)->metricsT(mi);
268                 dim_ += (*it)->dimensions();
269         }
270         return dim_;
271 }
272
273
274 void MathArray::drawT(TextPainter & pain, int x, int y) const
275 {
276         //if (drawn_ && x == xo_ && y == yo_)
277         //      return;
278         //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
279         xo_    = x;
280         yo_    = y;
281         drawn_ = true;
282
283         for (const_iterator it = begin(), et = end(); it != et; ++it) {
284                 (*it)->drawT(pain, x, y);
285                 x += (*it)->width();
286         }
287 }
288
289
290 int MathArray::pos2x(size_type pos) const
291 {
292         return pos2x(0, pos, 0);
293 }
294
295
296 int MathArray::pos2x(size_type pos1, size_type pos2, int glue) const
297 {
298         int x = 0;
299         size_type target = min(pos2, size());
300         for (size_type i = pos1; i < target; ++i) {
301                 const_iterator it = begin() + i;
302                 if ((*it)->getChar() == ' ')
303                         x += glue;
304                 x += (*it)->width();
305         }
306         return x;
307 }
308
309
310 MathArray::size_type MathArray::x2pos(int targetx) const
311 {
312         return x2pos(0, targetx, 0);
313 }
314
315
316 MathArray::size_type MathArray::x2pos(size_type startpos, int targetx,
317         int glue) const
318 {
319         const_iterator it = begin() + startpos;
320         int lastx = 0;
321         int currx = 0;
322         for (; currx < targetx && it < end(); ++it) {
323                 lastx = currx;
324                 if ((*it)->getChar() == ' ')
325                         currx += glue;
326                 currx += (*it)->width();
327         }
328         if (abs(lastx - targetx) < abs(currx - targetx) && it != begin() + startpos)
329                 --it;
330         return it - begin();
331 }
332
333
334 int MathArray::dist(int x, int y) const
335 {
336         int xx = 0;
337         int yy = 0;
338
339         if (x < xo_)
340                 xx = xo_ - x;
341         else if (x > xo_ + width())
342                 xx = x - xo_ - width();
343
344         if (y < yo_ - ascent())
345                 yy = yo_ - ascent() - y;
346         else if (y > yo_ + descent())
347                 yy = y - yo_ - descent();
348
349         return xx + yy;
350 }
351
352
353 void MathArray::boundingBox(int & x1, int & x2, int & y1, int & y2)
354 {
355         x1 = xo_;
356         x2 = xo_ + width();
357         y1 = yo_ - ascent();
358         y2 = yo_ + descent();
359 }
360
361 void MathArray::center(int & x, int & y) const
362 {
363         x = xo_ + width() / 2;
364         y = yo_ + (descent() - ascent()) / 2;
365 }
366
367
368 void MathArray::towards(int & x, int & y) const
369 {
370         int cx = 0;
371         int cy = 0;
372         center(cx, cy);
373
374         double r = 1.0;
375         //int dist = (x - cx) * (x - cx) + (y - cy) * (y - cy);
376
377         x = cx + int(r * (x - cx));
378         y = cy + int(r * (y - cy));
379 }
380
381
382 void MathArray::setXY(int x, int y) const
383 {
384         xo_ = x;
385         yo_ = y;
386 }
387
388
389 void MathArray::notifyCursorLeaves()
390 {
391         // do not recurse!
392
393         // remove base-only "scripts"
394         for (pos_type i = 0; i + 1 < size(); ++i) {
395                 MathScriptInset * p = operator[](i).nucleus()->asScriptInset();
396                 if (p && p->cell(0).empty() && p->cell(1).empty()) {
397                         MathArray ar = p->nuc();
398                         erase(i);
399                         insert(i, ar);
400                         mathcursor->adjust(i, ar.size() - 1);
401                 }
402         }
403
404         // glue adjacent font insets of the same kind
405         for (pos_type i = 0; i + 1 < size(); ++i) {
406                 MathFontInset * p = operator[](i).nucleus()->asFontInset();
407                 MathFontInset const * q = operator[](i + 1)->asFontInset();
408                 if (p && q && p->name() == q->name()) {
409                         p->cell(0).append(q->cell(0));
410                         erase(i + 1);
411                         mathcursor->adjust(i, -1);
412                 }
413         }
414
415 }