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