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