]> git.lyx.org Git - lyx.git/blob - src/mathed/math_xdata.C
some code shuffling. New 'Dimension' class instead of passing around three
[lyx.git] / src / mathed / math_xdata.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "math_scriptinset.h"
8 #include "math_support.h"
9 #include "frontends/Painter.h"
10 #include "textpainter.h"
11 #include "debug.h"
12
13
14 using std::max;
15 using std::min;
16 using std::abs;
17
18
19 extern MathScriptInset const * asScript(MathArray::const_iterator it);
20
21
22 MathXArray::MathXArray()
23         : xo_(0), yo_(0), clean_(false), drawn_(false)
24 {}
25
26
27 void MathXArray::touch() const
28 {
29         clean_  = false;
30         drawn_  = false;
31 }
32
33
34 void MathXArray::metrics(MathMetricsInfo & mi) const
35 {
36         //if (clean_)
37         //      return;
38
39         size_   = mi;
40         clean_  = true;
41         drawn_  = false;
42
43         if (data_.empty()) {
44                 mathed_char_dim(mi.base.font, 'I', dim_.a, dim_.d, dim_.w);
45                 return;
46         }
47
48         dim_.clear();
49         for (const_iterator it = begin(); it != end(); ++it) {
50                 MathInset const * p = it->nucleus();
51                 MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
52                 int ww, aa, dd;
53                 if (q) {
54                         q->metrics(p, mi);
55                         q->dimensions2(p, ww, aa, dd);
56                         ++it;
57                 } else {
58                         p->metrics(mi);
59                         p->dimensions(ww, aa, dd);
60                 }
61                 dim_ += Dimension(ww, aa, dd);
62         }
63
64         //lyxerr << "MathXArray::metrics(): '" << dim_ << "\n";
65 }
66
67
68 void MathXArray::metricsExternal(MathMetricsInfo & mi,
69         std::vector<Row> & v) const
70 {
71         //if (clean_)
72         //      return;
73
74         size_   = mi;
75         clean_  = true;
76         drawn_  = false;
77
78         if (data_.empty()) {
79                 mathed_char_dim(mi.base.font, 'I', dim_.a, dim_.d, dim_.w);
80                 return;
81         }
82
83         dim_.clear();
84         for (const_iterator it = begin(); it != end(); ++it) {
85                 MathInset const * p = it->nucleus();
86                 MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
87                 int ww, aa, dd;
88                 if (q) {
89                         q->metrics(p, mi);
90                         q->dimensions2(p, ww, aa, dd);
91                         ++it;
92                         v.push_back(Row());
93                         v.back().dim = Dimension(ww, aa, dd);
94                         v.push_back(Row());
95                 } else {
96                         p->metrics(mi);
97                         p->dimensions(ww, aa, dd);
98                         v.push_back(Row());
99                         v.back().dim = Dimension(ww, aa, dd);
100                 }
101         }
102
103         //lyxerr << "MathXArray::metrics(): '" << dim_ << "\n";
104 }
105
106
107 void MathXArray::draw(MathPainterInfo & pi, int x, int y) const
108 {
109         //if (drawn_ && x == xo_ && y == yo_)
110         //      return;
111
112         //lyxerr << "x: " << x << " y: " << y << " " << pain.workAreaHeight() << endl;
113
114         xo_    = x;
115         yo_    = y;
116         drawn_ = true;
117
118         if (y + descent() <= 0)                   // don't draw above the workarea
119                 return;
120         if (y - ascent() >= pi.pain.paperHeight())   // don't draw below the workarea
121                 return;
122         if (x + width() <= 0)                     // don't draw left of workarea
123                 return;
124         if (x >= pi.pain.paperWidth())              // don't draw right of workarea
125                 return;
126
127         const_iterator it = begin(), et = end();
128
129         if (it == et) {
130                 pi.pain.rectangle(x, y - ascent(), width(), height(), LColor::mathline);
131                 return;
132         }
133
134         for (; it != et; ++it) {
135                 MathInset const * p = it->nucleus();
136                 MathScriptInset const * q = (it + 1 == et) ? 0 : asScript(it);
137                 if (q) {
138                         q->draw(p, pi, x, y);
139                         x += q->width2(p);
140                         ++it;
141                 } else {
142                         p->draw(pi, x, y);
143                         x += p->width();
144                 }
145         }
146 }
147
148
149 void MathXArray::drawExternal(MathPainterInfo & pi, int x, int y,
150         std::vector<Row> const & v) const
151 {
152         for (size_type r = 0, pos = 0; r != v.size(); ++r) {
153                 int xx = x;
154                 int yy = y + v[r].yo;
155                 for ( ; pos != v[r].end; ++pos) {
156                         MathInset const * p = data_[pos].nucleus();
157                         MathScriptInset const * q = 0;
158                         if (pos + 1 != data_.size())
159                                 q = asScript(begin() + pos + 1);
160                         if (q) {
161                                 q->draw(p, pi, xx, yy);
162                                 xx += q->width2(p);
163                                 ++pos;
164                         } else {
165                                 p->draw(pi, xx, yy);
166                                 xx += p->width();
167                         }
168                 }
169         }
170 }
171
172
173 void MathXArray::metricsT(TextMetricsInfo const & mi) const
174 {
175         //if (clean_)
176         //      return;
177         dim_.clear();
178         for (const_iterator it = begin(); it != end(); ++it) {
179                 MathInset const * p = it->nucleus();
180                 MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
181                 int ww, aa, dd;
182                 if (q) {
183                         q->metricsT(p, mi);
184                         q->dimensions2(p, ww, aa, dd);
185                         ++it;
186                 } else {
187                         p->metricsT(mi);
188                         p->dimensions(ww, aa, dd);
189                 }
190                 dim_ += Dimension(ww, aa, dd);
191         }
192 }
193
194
195 void MathXArray::drawT(TextPainter & pain, int x, int y) const
196 {
197         //if (drawn_ && x == xo_ && y == yo_)
198         //      return;
199
200         //lyxerr << "x: " << x << " y: " << y << " " << pain.workAreaHeight() << endl;
201
202         xo_    = x;
203         yo_    = y;
204         drawn_ = true;
205
206         const_iterator it = begin(), et = end();
207
208         for (; it != et; ++it) {
209                 MathInset const * p = it->nucleus();
210                 MathScriptInset const * q = (it + 1 == et) ? 0 : asScript(it);
211                 if (q) {
212                         q->drawT(p, pain, x, y);
213                         x += q->width2(p);
214                         ++it;
215                 } else {
216                         p->drawT(pain, x, y);
217                         x += p->width();
218                 }
219         }
220 }
221
222
223 int MathXArray::pos2x(size_type targetpos) const
224 {
225         int x = 0;
226         const_iterator target = min(begin() + targetpos, end());
227         for (const_iterator it = begin(); it < target; ++it) {
228                 MathInset const * p = it->nucleus();
229                 MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
230                 if (q) {
231                         ++it;
232                         if (it < target)
233                                 x += q->width2(p);
234                         else  // "half" position
235                                 x += q->dxx(p) + q->nwid(p);
236                 } else
237                         x += p->width();
238         }
239         return x;
240 }
241
242
243 MathArray::size_type MathXArray::x2pos(int targetx) const
244 {
245         const_iterator it = begin();
246         int lastx = 0;
247         int currx = 0;
248         for (; currx < targetx && it < end(); ++it) {
249                 lastx = currx;
250
251                 int wid = 0;
252                 MathInset const * p = it->nucleus();
253                 MathScriptInset const * q = 0;
254                 if (it + 1 != end())
255                         q = asScript(it);
256                 if (q) {
257                         wid = q->width2(p);
258                         ++it;
259                 } else
260                         wid = p->width();
261
262                 currx += wid;
263         }
264         if (abs(lastx - targetx) < abs(currx - targetx) && it != begin())
265                 --it;
266         return it - begin();
267 }
268
269
270 int MathXArray::dist(int x, int y) const
271 {
272         int xx = 0;
273         int yy = 0;
274
275         if (x < xo_)
276                 xx = xo_ - x;
277         else if (x > xo_ + width())
278                 xx = x - xo_ - width();
279
280         if (y < yo_ - ascent())
281                 yy = yo_ - ascent() - y;
282         else if (y > yo_ + descent())
283                 yy = y - yo_ - descent();
284
285         return xx + yy;
286 }
287
288
289 void MathXArray::boundingBox(int & x1, int & x2, int & y1, int & y2)
290 {
291         x1 = xo_;
292         x2 = xo_ + width();
293         y1 = yo_ - ascent();
294         y2 = yo_ + descent();
295 }
296
297 /*
298 void MathXArray::findPos(MathPosFinder & f) const
299 {
300         double x = xo_;
301         double y = yo_;
302         for (const_iterator it = begin(); it < end(); ++it) {
303                 // check this position in the cell first
304                 f.visit(x, y);
305                 f.nextPos();
306
307                 // check inset
308                 MathInset const * p = it->nucleus();
309                 p->findPos(f);
310
311                 // move on
312                 MathScriptInset const * q = (it + 1 == end()) ? 0 : asScript(it);
313                 if (q) {
314                         x += q->width(p);
315                         f.nextPos();
316                         ++it;
317                 } else {
318                         x += p->width();
319                 }
320         }
321 }
322 */
323
324 void MathXArray::center(int & x, int & y) const
325 {
326         x = xo_ + width() / 2;
327         y = yo_ + (descent() - ascent()) / 2;
328 }
329
330
331 void MathXArray::towards(int & x, int & y) const
332 {
333         int cx = 0;
334         int cy = 0;
335         center(cx, cy);
336
337         double r = 1.0;
338         //int dist = (x - cx) * (x - cx) + (y - cy) * (y - cy);
339
340         x = cx + int(r * (x - cx));
341         y = cy + int(r * (y - cy));
342 }