]> git.lyx.org Git - lyx.git/blob - src/mathed/MathData.C
make it compile again (hopefully)
[lyx.git] / src / mathed / MathData.C
1 /**
2  * \file MathData.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 "MathData.h"
14 #include "InsetMathFont.h"
15 #include "InsetMathScript.h"
16 #include "InsetMathMacro.h"
17 #include "MathMacroTable.h"
18 #include "MathMLStream.h"
19 #include "MathSupport.h"
20 #include "MathReplace.h"
21
22 #include "BufferView.h"
23 #include "buffer.h"
24 #include "cursor.h"
25 #include "debug.h"
26 #include "LColor.h"
27
28 #include "frontends/Painter.h"
29
30 #include <boost/assert.hpp>
31
32 using lyx::odocstream;
33
34 using std::abs;
35 using std::endl;
36 using std::min;
37 using std::ostringstream;
38 using std::string;
39 using std::vector;
40
41
42 MathArray::MathArray()
43 {}
44
45
46 MathArray::MathArray(const_iterator from, const_iterator to)
47         : base_type(from, to)
48 {}
49
50
51 MathAtom & MathArray::operator[](pos_type pos)
52 {
53         BOOST_ASSERT(pos < size());
54         return base_type::operator[](pos);
55 }
56
57
58 MathAtom const & MathArray::operator[](pos_type pos) const
59 {
60         BOOST_ASSERT(pos < size());
61         return base_type::operator[](pos);
62 }
63
64
65 void MathArray::insert(size_type pos, MathAtom const & t)
66 {
67         base_type::insert(begin() + pos, t);
68 }
69
70
71 void MathArray::insert(size_type pos, MathArray const & ar)
72 {
73         BOOST_ASSERT(pos <= size());
74         base_type::insert(begin() + pos, ar.begin(), ar.end());
75 }
76
77
78 void MathArray::append(MathArray const & ar)
79 {
80         insert(size(), ar);
81 }
82
83
84 void MathArray::erase(size_type pos)
85 {
86         if (pos < size())
87                 erase(pos, pos + 1);
88 }
89
90
91 void MathArray::erase(iterator pos1, iterator pos2)
92 {
93         base_type::erase(pos1, pos2);
94 }
95
96
97 void MathArray::erase(iterator pos)
98 {
99         base_type::erase(pos);
100 }
101
102
103 void MathArray::erase(size_type pos1, size_type pos2)
104 {
105         base_type::erase(begin() + pos1, begin() + pos2);
106 }
107
108
109 void MathArray::dump2() const
110 {
111         lyx::odocstringstream os;
112         NormalStream ns(os);
113         for (const_iterator it = begin(); it != end(); ++it)
114                 ns << *it << ' ';
115         lyxerr << lyx::to_utf8(os.str());
116 }
117
118
119 void MathArray::dump() const
120 {
121         lyx::odocstringstream os;
122         NormalStream ns(os);
123         for (const_iterator it = begin(); it != end(); ++it)
124                 ns << '<' << *it << '>';
125         lyxerr << lyx::to_utf8(os.str());
126 }
127
128
129 void MathArray::validate(LaTeXFeatures & features) const
130 {
131         for (const_iterator it = begin(); it != end(); ++it)
132                 (*it)->validate(features);
133 }
134
135
136 bool MathArray::match(MathArray const & ar) const
137 {
138         return size() == ar.size() && matchpart(ar, 0);
139 }
140
141
142 bool MathArray::matchpart(MathArray const & ar, pos_type pos) const
143 {
144         if (size() < ar.size() + pos)
145                 return false;
146         const_iterator it = begin() + pos;
147         for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it)
148                 if (asString(*it) != asString(*jt))
149                         return false;
150         return true;
151 }
152
153
154 void MathArray::replace(ReplaceData & rep)
155 {
156         for (size_type i = 0; i < size(); ++i) {
157                 if (find1(rep.from, i)) {
158                         // match found
159                         lyxerr << "match found!" << endl;
160                         erase(i, i + rep.from.size());
161                         insert(i, rep.to);
162                 }
163         }
164
165 #ifdef WITH_WARNINGS
166 #warning temporarily disabled
167         // for (const_iterator it = begin(); it != end(); ++it)
168         //      it->nucleus()->replace(rep);
169 #endif
170 }
171
172
173 bool MathArray::find1(MathArray const & ar, size_type pos) const
174 {
175         lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl;
176         for (size_type i = 0, n = ar.size(); i < n; ++i)
177                 if (asString(operator[](pos + i)) != asString(ar[i]))
178                         return false;
179         return true;
180 }
181
182
183 MathArray::size_type MathArray::find(MathArray const & ar) const
184 {
185         for (int i = 0, last = size() - ar.size(); i < last; ++i)
186                 if (find1(ar, i))
187                         return i;
188         return size();
189 }
190
191
192 MathArray::size_type MathArray::find_last(MathArray const & ar) const
193 {
194         for (int i = size() - ar.size(); i >= 0; --i)
195                 if (find1(ar, i))
196                         return i;
197         return size();
198 }
199
200
201 bool MathArray::contains(MathArray const & ar) const
202 {
203         if (find(ar) != size())
204                 return true;
205         for (const_iterator it = begin(); it != end(); ++it)
206                 if ((*it)->contains(ar))
207                         return true;
208         return false;
209 }
210
211
212 void MathArray::touch() const
213 {
214 }
215
216
217 void MathArray::metrics(MetricsInfo & mi, Dimension & dim) const
218 {
219         metrics(mi);
220         dim = dim_;
221 }
222
223
224 namespace {
225
226 bool isInside(DocIterator const & it, MathArray const & ar,
227         lyx::pos_type p1, lyx::pos_type p2)
228 {
229         for (size_t i = 0; i != it.depth(); ++i) {
230                 CursorSlice const & sl = it[i];
231                 if (sl.inset().inMathed() && &sl.cell() == &ar)
232                         return p1 <= sl.pos() && sl.pos() < p2;
233         }
234         return false;
235 }
236
237 }
238
239
240
241 void MathArray::metrics(MetricsInfo & mi) const
242 {
243         mathed_char_dim(mi.base.font, 'I', dim_);
244
245         if (empty())
246                 return;
247
248         dim_.wid = 0;
249         Dimension d;
250         //BufferView & bv  = *mi.base.bv;
251         //Buffer const & buf = *bv.buffer();
252         for (size_t i = 0, n = size(); i != n; ++i) {
253                 MathAtom const & at = operator[](i);
254 #if 0
255                 MathMacro const * mac = at->asMacro();
256                 if (mac && buf.hasMacro(mac->name())) {
257                         MacroData const & tmpl = buf.getMacro(mac->name());
258                         int numargs = tmpl.numargs();
259                         if (i + numargs > n)
260                                 numargs = n - i - 1;
261                         lyxerr << "metrics:found macro: " << mac->name()
262                                 << " numargs: " << numargs << endl;
263                         if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
264                                 MathArray args(begin() + i + 1, begin() + i + numargs + 1);
265                                 MathArray exp;
266                                 tmpl.expand(args, exp);
267                                 mac->setExpansion(exp, args);
268                                 mac->metricsExpanded(mi, d);
269                                 dim_.wid += mac->widthExpanded();
270                                 i += numargs;
271                                 continue;
272                         }
273                 }
274 #endif
275                 at->metrics(mi, d);
276                 dim_ += d;
277         }
278 }
279
280
281 void MathArray::draw(PainterInfo & pi, int x, int y) const
282 {
283         //lyxerr << "MathArray::draw: x: " << x << " y: " << y << endl;
284         setXY(*pi.base.bv, x, y);
285
286         if (empty()) {
287                 pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline);
288                 return;
289         }
290
291         // don't draw outside the workarea
292         if (y + descent() <= 0
293                 || y - ascent() >= pi.pain.paperHeight()
294                 || x + width() <= 0
295                 || x >= pi.pain.paperWidth())
296                 return;
297
298         //BufferView & bv  = *pi.base.bv;
299         for (size_t i = 0, n = size(); i != n; ++i) {
300                 MathAtom const & at = operator[](i);
301 #if 0
302         Buffer const & buf = *bv.buffer();
303                 // special macro handling
304                 MathMacro const * mac = at->asMacro();
305                 if (mac && buf.hasMacro(mac->name())) {
306                         MacroData const & tmpl = buf.getMacro(mac->name());
307                         int numargs = tmpl.numargs();
308                         if (i + numargs > n)
309                                 numargs = n - i - 1;
310                         if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
311                                 mac->drawExpanded(pi, x, y);
312                                 x += mac->widthExpanded();
313                                 i += numargs;
314                                 continue;
315                         }
316                 }
317 #endif
318                 //BufferView & bv  = *pi.base.bv;
319                 pi.base.bv->coordCache().insets().add(at.nucleus(), x, y);
320                 at->drawSelection(pi, x, y);
321                 at->draw(pi, x, y);
322                 x += at->width();
323         }
324 }
325
326
327 void MathArray::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
328 {
329         dim.clear();
330         Dimension d;
331         for (const_iterator it = begin(); it != end(); ++it) {
332                 (*it)->metricsT(mi, d);
333                 dim += d;
334         }
335 }
336
337
338 void MathArray::drawT(TextPainter & pain, int x, int y) const
339 {
340         //lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
341
342         // FIXME: Abdel 16/10/2006
343         // This drawT() method is never used, this is dead code.
344
345         for (const_iterator it = begin(), et = end(); it != et; ++it) {
346                 (*it)->drawT(pain, x, y);
347                 //x += (*it)->width_;
348                 x += 2;
349         }
350 }
351
352
353 int MathArray::pos2x(size_type pos) const
354 {
355         return pos2x(pos, 0);
356 }
357
358
359 int MathArray::pos2x(size_type pos, int glue) const
360 {
361         int x = 0;
362         size_type target = min(pos, size());
363         for (size_type i = 0; i < target; ++i) {
364                 const_iterator it = begin() + i;
365                 if ((*it)->getChar() == ' ')
366                         x += glue;
367                 //lyxerr << "char: " << (*it)->getChar()
368                 //      << "width: " << (*it)->width() << std::endl;
369                 x += (*it)->width();
370         }
371         return x;
372 }
373
374
375 MathArray::size_type MathArray::x2pos(int targetx) const
376 {
377         return x2pos(targetx, 0);
378 }
379
380
381 MathArray::size_type MathArray::x2pos(int targetx, int glue) const
382 {
383         const_iterator it = begin();
384         int lastx = 0;
385         int currx = 0;
386         // find first position after targetx
387         for (; currx < targetx && it < end(); ++it) {
388                 lastx = currx;
389                 if ((*it)->getChar() == ' ')
390                         currx += glue;
391                 currx += (*it)->width();
392         }
393
394         /**
395          * If we are not at the beginning of the array, go to the left
396          * of the inset if one of the following two condition holds:
397          * - the current inset is editable (so that the cursor tip is
398          *   deeper than us): in this case, we want all intermediate
399          *   cursor slices to be before insets;
400          * - the mouse is closer to the left side of the inset than to
401          *   the right one.
402          * See bug 1918 for details.
403          **/
404         if (it != begin() && currx >= targetx
405             && ((*boost::prior(it))->asNestInset()
406                 || abs(lastx - targetx) < abs(currx - targetx))) {
407                 --it;
408         }
409
410         return it - begin();
411 }
412
413
414 int MathArray::dist(BufferView & bv, int x, int y) const
415 {
416         int xx = 0;
417         int yy = 0;
418
419         const int xo_ = xo(bv);
420         const int yo_ = yo(bv);
421
422         if (x < xo_)
423                 xx = xo_ - x;
424         else if (x > xo_ + width())
425                 xx = x - xo_ - width();
426
427         if (y < yo_ - ascent())
428                 yy = yo_ - ascent() - y;
429         else if (y > yo_ + descent())
430                 yy = y - yo_ - descent();
431
432         return xx + yy;
433 }
434
435
436 void MathArray::setXY(BufferView & bv, int x, int y) const
437 {
438         //lyxerr << "setting position cache for MathArray " << this << std::endl;
439         bv.coordCache().arrays().add(this, x, y);
440 }
441
442
443 int MathArray::xo(BufferView & bv) const
444 {
445         return bv.coordCache().getArrays().x(this);
446 }
447
448
449 int MathArray::yo(BufferView & bv) const
450 {
451         return bv.coordCache().getArrays().y(this);
452 }
453
454
455 std::ostream & operator<<(std::ostream & os, MathArray const & ar)
456 {
457         lyx::odocstringstream oss;
458         NormalStream ns(oss);
459         ns << ar;
460         return os << lyx::to_utf8(oss.str());
461 }
462
463
464 odocstream & operator<<(odocstream & os, MathArray const & ar)
465 {
466         NormalStream ns(os);
467         ns << ar;
468         return os;
469 }