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