]> git.lyx.org Git - features.git/blob - src/mathed/math_iter.C
mathed25.diff
[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(int pos1, int pos2)
385 {
386         if (!array) {
387         //      lyxerr << "Math error: Attempting to copy a void array." << endl;
388                 return 0;
389         }
390
391         ipush();
392         MathedArray * t = array;
393         MathedArray * a;
394
395         if (pos1 > 0 || pos2 <= array->last()) {
396                 short fc = 0;
397                 if (pos1 > 0 && (*array)[pos1] > ' ') {
398                         for (int p = pos1; p >= 0; --p) {
399                                 if (MathIsFont((*array)[p])) {
400                                 if (p != pos1 - 1)
401                                 fc = (*array)[p];
402                                 else
403                                 --pos1;
404                                 break;
405                                 }
406                         }
407                 }
408
409                 if (pos2 > 0 && (*array)[pos2] >= ' '
410                              && MathIsFont((*array)[pos2 - 1]))
411                         --pos2;
412
413                 int dx = pos2 - pos1;
414                 a = new MathedArray;
415                 a->resize(dx + 1);
416                 //       lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
417                 array->strange_copy(a, (fc) ? 1 : 0, pos1, dx);
418                 if (fc) {
419                         (*a)[0] = fc;
420                         ++dx;
421                 }
422                 a->last(dx);
423                 (*a)[dx] = '\0';
424         } else
425                 a = new MathedArray(*array);
426
427         SetData(a);
428         while (OK()) {
429                 if (IsInset()) {
430                         MathedInset * inset = GetInset();
431                         inset = inset->Clone();
432                         array->raw_pointer_insert(inset, pos + 1, sizeof(inset));
433                 }
434                 Next();
435         }
436         array = t;
437         ipop();
438         return a;
439 }
440
441
442 void MathedIter::Clear()
443 {
444         if (!array) {
445                 lyxerr << "Math error: Attempting to clean a void array." << endl;
446                 return;
447         }
448
449         Reset();
450         while (OK()) {
451                 if (IsInset()) {
452                         MathedInset * inset = GetInset();
453                         if (inset->GetType()!= LM_OT_MACRO_ARG)
454                         delete inset;
455                         Delete();
456                 } else
457                         Next();
458         }
459 }
460
461
462 // Check consistency of tabs and crs
463 void MathedIter::checkTabs()
464 {
465         ipush();
466
467         // MathedIter:Reset();
468         while (OK()) {
469                 if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
470                         Delete();
471                         continue;
472                 }
473
474                 if (IsCR() && col < ncols - 2) 
475                         insert(' ', LM_TC_TAB);
476
477                 MathedIter::Next();
478         }
479
480         if (col < ncols - 2)
481                 insert(' ', LM_TC_TAB);
482         
483         ipop();
484 }
485
486
487 //  Try to adjust tabs in the expected place, as used in eqnarrays
488 //  Rules:
489 //   - If there are a relation operator, put tabs around it
490 //   - If tehre are not a relation operator, put everything in the
491 //     3rd column.
492 void MathedIter::adjustTabs()
493 {}
494
495
496 bool MathedIter::IsInset() const
497 {
498         return MathIsInset((*array)[pos]);
499 }
500
501
502 bool MathedIter::IsActive() const
503 {
504         return MathIsActive((*array)[pos]);
505 }
506
507
508 bool MathedIter::IsFont() const
509 {
510         return MathIsFont((*array)[pos]);
511 }
512
513
514 bool MathedIter::IsScript() const
515 {
516         return MathIsScript((*array)[pos]);
517 }
518
519
520 bool MathedIter::IsTab() const
521 {
522         return ((*array)[pos] == LM_TC_TAB);
523 }
524
525
526 bool MathedIter::IsCR() const
527 {
528         return ((*array)[pos] == LM_TC_CR);
529 }
530
531
532 MathedIter::MathedIter(MathedArray * d)
533         : array(d)
534 {
535         pos = 0;
536         row = 0;
537         col = 0;
538         fcode( (array && IsFont()) ? (*array)[0] : 0 );
539 }
540
541
542 void MathedIter::ipush()
543 {
544         stck.fcode = fcode();
545         stck.pos = pos;
546         stck.row = row;
547         stck.col = col;
548 }
549
550
551 void MathedIter::ipop()
552 {
553         fcode(stck.fcode);
554         pos = stck.pos;
555         row = stck.row;
556         col = stck.col;
557 }