]> git.lyx.org Git - lyx.git/blob - src/mathed/math_iter.C
mathed20.diff
[lyx.git] / src / mathed / math_iter.C
1 /*
2  *  File:        math_inset.C
3  *  Purpose:     Implementation of insets for mathed
4  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5  *  Created:     January 1996
6  *  Description:
7  *
8  *  Dependencies: Xlib, XForms
9  *
10  *  Copyright: 1996, Alejandro Aguilar Sierra
11  *
12  *   Version: 0.8beta.
13  *
14  *   You are free to use and modify this code under the terms of
15  *   the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19
20 #ifdef __GNUG__
21 #pragma implementation
22 #endif
23
24 #include "math_iter.h"
25 #include "array.h"
26 #include "math_inset.h"
27 #include "symbol_def.h"
28 #include "support/lstrings.h"
29 #include "debug.h"
30 #include "mathed/support.h"
31
32 using std::endl;
33
34 const int SizeInset = sizeof(char*) + 2;
35
36 //extern int mathed_char_width(short type, int style, byte c);
37 //extern int mathed_string_width(short type, int style, string const & s);
38 //extern int mathed_char_height(short, int, byte, int &, int &);
39
40
41 MathedIter::MathedIter()
42         : flags(0), fcode(0), pos(0), row(0), col(0), ncols(0), array(0)
43 {}
44
45
46 void MathedIter::SetData(MathedArray * a)
47 {
48         array = a; Reset();
49 }
50
51
52 MathedArray * MathedIter::GetData() const
53 {
54         return array;
55 }
56
57
58 int MathedIter::Empty() const
59 {
60         return array->last() <= 1;
61 }
62
63
64 int MathedIter::OK() const
65 {
66         return array && (pos < array->last());
67 }
68
69
70 void MathedIter::Reset()
71 {
72         if (array->last() > 0 && MathIsFont((*array)[0])) {
73                 fcode = (*array)[0];
74                 pos   = 1;
75         } else {
76                 fcode = -1;
77                 pos   = 0;
78         }
79         col = 0;
80         row = 0;
81 }
82
83
84 byte MathedIter::GetChar() const
85 {
86         if (IsFont()) {
87                 fcode = (*array)[pos];
88                 ++pos;
89         }
90         return (*array)[pos];
91 }
92
93
94 string const MathedIter::GetString() const
95 {
96         if (IsFont()) {
97                 fcode = (*array)[++pos];
98                 ++pos;
99         }
100
101         string s;
102         for (; (*array)[pos] >= ' ' && pos < array->last(); ++pos)
103                 s += (*array)[pos];
104
105         return s;
106 }
107
108
109 MathedInset * MathedIter::GetInset() const
110 {
111         if (IsInset()) {
112                 MathedInset * p;
113                 array->raw_pointer_copy(&p, pos + 1);
114                 return p;
115         } else {
116                 lyxerr << "Math Error: This is not an inset["
117                        << (*array)[pos] << "]" << endl;
118                 return 0;
119         }
120 }
121
122
123 // An active math inset MUST be derived from MathParInset because it
124 // must have at least one paragraph to edit
125 MathParInset * MathedIter::GetActiveInset() const
126 {
127         if (IsActive()) 
128                 return reinterpret_cast<MathParInset*>(GetInset());
129
130         lyxerr << "Math Error: This is not an active inset" << endl;
131         return 0;
132 }
133
134
135 bool MathedIter::Next()
136 {
137         if (!OK())
138                 return false;
139
140         if ((*array)[pos] < ' ') {
141                 fcode = -1;
142                 if (IsTab())
143                         ++col;
144                 if (IsCR()) {
145                         col = 0;
146                         ++row;
147                 }
148         }
149
150         if (IsInset())
151                 pos += sizeof(char*) + 2;
152         else
153                 ++pos;
154
155         if (IsFont()) 
156                 fcode = (*array)[pos++];
157
158         return true;
159 }
160
161
162 bool MathedIter::goNextCode(MathedTextCodes code)
163 {
164         while (Next()) {
165                 if ((*array)[pos] == code)
166                         return true;
167         }
168
169         return false;
170 }
171
172
173 void MathedIter::goPosAbs(int p)
174 {
175         Reset();
176         while (pos < p && Next())
177                 ;
178 }
179
180
181 void MathedIter::Insert(byte c, MathedTextCodes t)
182 {
183         if (c < ' ')
184                 return;
185
186         if (t == LM_TC_TAB && col >= ncols - 1)
187                 return;
188
189         // Never more than one space // array->bf[pos-1] gives error from purify:
190         // Reading 1 byte from 0x47b857 in the heap.
191         //
192         // Address 0x47b857 is 1 byte before start of malloc'd block at
193         // 0x47b858 of 16 bytes.
194
195         if (c == ' ' && ((*array)[pos] == ' ' || (*array)[pos - 1] == ' '))
196                 return;
197
198         if (IsFont() && (*array)[pos] == t) {
199                 fcode = t;
200                 ++pos;
201         } else {
202                 if (t != fcode && pos > 0 && MathIsFont((*array)[pos - 1])) {
203                         --pos;
204                         int k = pos - 1;
205                         for (; k >= 0 && (*array)[k] >= ' '; --k)
206                                 ;
207                         fcode = (k >= 0 && MathIsFont((*array)[k])) ? (*array)[k] : -1;
208                 }
209         }
210
211         short const f = ((*array)[pos] < ' ') ? 0 : fcode;
212         int shift = (t == fcode) ? 1 : ((f) ? 3 : 2);
213
214         if (t == LM_TC_TAB || t == LM_TC_CR) {
215                 --shift;
216                 c = t;
217                 if (t == LM_TC_CR) {
218                         ++row;
219                         col = 0;
220                 } else
221                         ++col;
222         }
223
224         if (pos < array->last())
225                 array->move(pos, shift);
226         else {
227                 array->need_size(array->last() + shift);
228                 array->last(array->last() + shift);
229                 (*array)[array->last()] = '\0';
230         }
231
232         if (t != fcode) {
233                 if (f)
234                         (*array)[pos + shift - 1] = fcode;
235
236                 if (c >= ' ') {
237                         (*array)[pos++] = t;
238                         fcode = t;
239                 } else 
240                         fcode = 0;
241         }
242
243         (*array)[pos++] = c;
244 }
245
246
247 // Prepare to insert a non-char object
248 void MathedIter::split(int shift)
249 {
250         if (pos < array->last()) {
251
252                 bool fg = false;
253                 if ((*array)[pos] >= ' ') {
254                         if (pos> 0 && MathIsFont((*array)[pos - 1]))
255                                 --pos;
256                         else {
257                                 fg = true;
258                                 ++shift;
259                         }
260                 }
261
262                 array->move(pos, shift);
263
264                 if (fg)
265                         (*array)[pos + shift - 1] = fcode;
266
267         } else {
268
269                 array->need_size(array->last() + shift);
270                 array->last(array->last() + shift);
271         }
272
273         (*array)[array->last()] = '\0';
274 }
275
276
277 // I assume that both pos and pos2 are legal positions
278 void MathedIter::join(int pos2)
279 {
280         if (!OK() || pos2 <= pos)
281                 return;
282
283         short f = fcode;
284         if (pos > 0 && (*array)[pos] >= ' ' && MathIsFont((*array)[pos - 1]))
285                 --pos;  
286
287         if (MathIsFont((*array)[pos2 - 1]))
288                 --pos2;
289
290         if ((*array)[pos2] >= ' ') {
291                 for (int p = pos2; p > 0; --p) {
292                         if (MathIsFont((*array)[p])) {
293                                 f = (*array)[p];
294                                 break;
295                         }
296                 }
297                 (*array)[pos++] = f;
298         }
299
300         array->move(pos2, pos - pos2);
301 }
302
303
304 void MathedIter::Insert(MathedInset * p, int type)
305 {
306         int const shift = SizeInset;
307
308         if (!MathIsInset(type))
309                 type = LM_TC_INSET;
310
311         split(shift);
312
313         (*array)[pos] = type;
314         array->raw_pointer_insert(p, pos + 1, sizeof(p));
315         pos += SizeInset;
316         (*array)[pos - 1] = type;
317         (*array)[array->last()] = '\0';
318         fcode = -1;
319 }
320
321
322 bool MathedIter::Delete()
323 {
324         if (!OK())
325                 return false;
326
327         int shift = 0;
328         byte c = GetChar();
329         if (c >= ' ') {
330
331                 if (MathIsFont((*array)[pos - 1]) && (*array)[pos + 1] < ' ') {
332                         shift = 2;
333                         pos--;
334                         int i = pos - 1;
335                         for (; i > 0 && !MathIsFont((*array)[i]); --i)
336                                 ;
337                         if (i > 0 && MathIsFont((*array)[i]))
338                         fcode = (*array)[i];
339                 } else
340                         shift = 1;
341
342         } else {
343
344                 if (MathIsInset((*array)[pos]))
345                         shift = sizeof(char*) + 2;
346                 else if (c == LM_TC_TAB || c == LM_TC_CR) {
347                         ++shift;
348                 //       lyxerr <<"Es un tab.";
349                 } else {
350                         lyxerr << "Math Warning: expected inset." << endl;
351                 }
352
353         }
354
355         if (shift != 0) {
356                 array->move(pos + shift, -shift);
357                 if (pos >= array->last())
358                         pos = (array->last() > 0) ? array->last() : 0;
359                 return true;
360         } else
361                 return false;
362 }
363
364
365 MathedArray * MathedIter::Copy(int pos1, int pos2)
366 {
367         if (!array) {
368         //      lyxerr << "Math error: Attempting to copy a void array." << endl;
369                 return 0;
370         }
371
372         ipush();
373         MathedArray * t = array;
374         MathedArray * a;
375
376         if (pos1 > 0 || pos2 <= array->last()) {
377                 short fc = 0;
378                 if (pos1 > 0 && (*array)[pos1] > ' ') {
379                         for (int p = pos1; p >= 0; --p) {
380                                 if (MathIsFont((*array)[p])) {
381                                 if (p != pos1 - 1)
382                                 fc = (*array)[p];
383                                 else
384                                 --pos1;
385                                 break;
386                                 }
387                         }
388                 }
389
390                 if (pos2 > 0 && (*array)[pos2] >= ' '
391                              && MathIsFont((*array)[pos2 - 1]))
392                         --pos2;
393
394                 int dx = pos2 - pos1;
395                 a = new MathedArray(dx + MathedArray::ARRAY_MIN_SIZE);
396                 //       lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
397                 array->strange_copy(a, (fc) ? 1 : 0, pos1, dx);
398                 if (fc) {
399                         (*a)[0] = fc;
400                         ++dx;
401                 }
402                 a->last(dx);
403                 (*a)[dx] = '\0';
404         } else
405                 a = new MathedArray(*array);
406
407         SetData(a);
408         while (OK()) {
409                 if (IsInset()) {
410                         MathedInset * inset = GetInset();
411                         inset = inset->Clone();
412                         array->raw_pointer_insert(inset, pos + 1, sizeof(inset));
413                 }
414                 Next();
415         }
416         array = t;
417         ipop();
418         return a;
419 }
420
421
422 void MathedIter::Clear()
423 {
424         if (!array) {
425                 lyxerr << "Math error: Attempting to clean a void array." << endl;
426                 return;
427         }
428
429         Reset();
430         while (OK()) {
431                 if (IsInset()) {
432                         MathedInset * inset = GetInset();
433                         if (inset->GetType()!= LM_OT_MACRO_ARG)
434                         delete inset;
435                         Delete();
436                 } else
437                         Next();
438         }
439 }
440
441
442 // Check consistency of tabs and crs
443 void MathedIter::checkTabs()
444 {
445         ipush();
446
447         // MathedIter:Reset();
448         while (OK()) {
449                 if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
450                         Delete();
451                         continue;
452                 }
453
454                 if (IsCR() && col < ncols - 2) 
455                         Insert(' ', LM_TC_TAB);
456
457                 MathedIter::Next();
458         }
459
460         if (col < ncols - 2)
461                 Insert(' ', LM_TC_TAB);
462         
463         ipop();
464 }
465
466
467 //  Try to adjust tabs in the expected place, as used in eqnarrays
468 //  Rules:
469 //   - If there are a relation operator, put tabs around it
470 //   - If tehre are not a relation operator, put everything in the
471 //     3rd column.
472 void MathedIter::adjustTabs()
473 {}
474
475
476 bool MathedIter::IsInset() const
477 {
478         return MathIsInset((*array)[pos]);
479 }
480
481
482 bool MathedIter::IsActive() const
483 {
484         return MathIsActive((*array)[pos]);
485 }
486
487
488 bool MathedIter::IsFont() const
489 {
490         return MathIsFont((*array)[pos]);
491 }
492
493
494 bool MathedIter::IsScript() const
495 {
496         return MathIsScript((*array)[pos]);
497 }
498
499
500 bool MathedIter::IsTab() const
501 {
502         return ((*array)[pos] == LM_TC_TAB);
503 }
504
505
506 bool MathedIter::IsCR() const
507 {
508         return ((*array)[pos] == LM_TC_CR);
509 }
510
511
512 MathedIter::MathedIter(MathedArray * d)
513         : array(d)
514 {
515         pos = 0;
516         row = 0;
517         col = 0;
518         fcode = (array && IsFont()) ? (*array)[0]: 0;
519 }
520
521
522 void MathedIter::ipush()
523 {
524         stck.fcode = fcode;
525         stck.pos = pos;
526         stck.row = row;
527         stck.col = col;
528 }
529
530
531 void MathedIter::ipop()
532 {
533         fcode = stck.fcode;
534         pos = stck.pos;
535         row = stck.row;
536         col = stck.col;
537 }