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