]> git.lyx.org Git - features.git/blob - src/mathed/math_iter.C
9ba085e84eddcbcf0a4b8ed6113eae3f2b1ec4cd
[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::Insert(MathedInset * p, int type)
315 {
316         int const shift = SizeInset;
317
318         if (!MathIsInset(type))
319                 type = LM_TC_INSET;
320
321         split(shift);
322
323         (*array)[pos] = type;
324         array->raw_pointer_insert(p, pos + 1, sizeof(p));
325         pos += SizeInset;
326         (*array)[pos - 1] = type;
327         (*array)[array->last()] = '\0';
328         fcode(-1);
329 }
330
331
332 bool MathedIter::Delete()
333 {
334         if (!OK())
335                 return false;
336
337         int shift = 0;
338         byte c = GetChar();
339         if (c >= ' ') {
340
341                 if (MathIsFont((*array)[pos - 1]) && (*array)[pos + 1] < ' ') {
342                         shift = 2;
343                         pos--;
344                         int i = pos - 1;
345                         for (; i > 0 && !MathIsFont((*array)[i]); --i)
346                                 ;
347                         if (i > 0 && MathIsFont((*array)[i]))
348                         fcode((*array)[i]);
349                 } else
350                         shift = 1;
351
352         } else {
353
354                 if (MathIsInset((*array)[pos]))
355                         shift = sizeof(char*) + 2;
356                 else if (c == LM_TC_TAB || c == LM_TC_CR) {
357                         ++shift;
358                 //       lyxerr <<"Es un tab.";
359                 } else {
360                         lyxerr << "Math Warning: expected inset." << endl;
361                 }
362
363         }
364
365         if (shift != 0) {
366                 array->move(pos + shift, -shift);
367                 if (pos >= array->last())
368                         pos = (array->last() > 0) ? array->last() : 0;
369                 return true;
370         } else
371                 return false;
372 }
373
374
375 MathedArray * MathedIter::Copy(int pos1, int pos2)
376 {
377         if (!array) {
378         //      lyxerr << "Math error: Attempting to copy a void array." << endl;
379                 return 0;
380         }
381
382         ipush();
383         MathedArray * t = array;
384         MathedArray * a;
385
386         if (pos1 > 0 || pos2 <= array->last()) {
387                 short fc = 0;
388                 if (pos1 > 0 && (*array)[pos1] > ' ') {
389                         for (int p = pos1; p >= 0; --p) {
390                                 if (MathIsFont((*array)[p])) {
391                                 if (p != pos1 - 1)
392                                 fc = (*array)[p];
393                                 else
394                                 --pos1;
395                                 break;
396                                 }
397                         }
398                 }
399
400                 if (pos2 > 0 && (*array)[pos2] >= ' '
401                              && MathIsFont((*array)[pos2 - 1]))
402                         --pos2;
403
404                 int dx = pos2 - pos1;
405                 a = new MathedArray(dx + MathedArray::ARRAY_MIN_SIZE);
406                 //       lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
407                 array->strange_copy(a, (fc) ? 1 : 0, pos1, dx);
408                 if (fc) {
409                         (*a)[0] = fc;
410                         ++dx;
411                 }
412                 a->last(dx);
413                 (*a)[dx] = '\0';
414         } else
415                 a = new MathedArray(*array);
416
417         SetData(a);
418         while (OK()) {
419                 if (IsInset()) {
420                         MathedInset * inset = GetInset();
421                         inset = inset->Clone();
422                         array->raw_pointer_insert(inset, pos + 1, sizeof(inset));
423                 }
424                 Next();
425         }
426         array = t;
427         ipop();
428         return a;
429 }
430
431
432 void MathedIter::Clear()
433 {
434         if (!array) {
435                 lyxerr << "Math error: Attempting to clean a void array." << endl;
436                 return;
437         }
438
439         Reset();
440         while (OK()) {
441                 if (IsInset()) {
442                         MathedInset * inset = GetInset();
443                         if (inset->GetType()!= LM_OT_MACRO_ARG)
444                         delete inset;
445                         Delete();
446                 } else
447                         Next();
448         }
449 }
450
451
452 // Check consistency of tabs and crs
453 void MathedIter::checkTabs()
454 {
455         ipush();
456
457         // MathedIter:Reset();
458         while (OK()) {
459                 if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
460                         Delete();
461                         continue;
462                 }
463
464                 if (IsCR() && col < ncols - 2) 
465                         Insert(' ', LM_TC_TAB);
466
467                 MathedIter::Next();
468         }
469
470         if (col < ncols - 2)
471                 Insert(' ', LM_TC_TAB);
472         
473         ipop();
474 }
475
476
477 //  Try to adjust tabs in the expected place, as used in eqnarrays
478 //  Rules:
479 //   - If there are a relation operator, put tabs around it
480 //   - If tehre are not a relation operator, put everything in the
481 //     3rd column.
482 void MathedIter::adjustTabs()
483 {}
484
485
486 bool MathedIter::IsInset() const
487 {
488         return MathIsInset((*array)[pos]);
489 }
490
491
492 bool MathedIter::IsActive() const
493 {
494         return MathIsActive((*array)[pos]);
495 }
496
497
498 bool MathedIter::IsFont() const
499 {
500         return MathIsFont((*array)[pos]);
501 }
502
503
504 bool MathedIter::IsScript() const
505 {
506         return MathIsScript((*array)[pos]);
507 }
508
509
510 bool MathedIter::IsTab() const
511 {
512         return ((*array)[pos] == LM_TC_TAB);
513 }
514
515
516 bool MathedIter::IsCR() const
517 {
518         return ((*array)[pos] == LM_TC_CR);
519 }
520
521
522 MathedIter::MathedIter(MathedArray * d)
523         : array(d)
524 {
525         pos = 0;
526         row = 0;
527         col = 0;
528         fcode( (array && IsFont()) ? (*array)[0] : 0 );
529 }
530
531
532 void MathedIter::ipush()
533 {
534         stck.fcode = fcode();
535         stck.pos = pos;
536         stck.row = row;
537         stck.col = col;
538 }
539
540
541 void MathedIter::ipop()
542 {
543         fcode(stck.fcode);
544         pos = stck.pos;
545         row = stck.row;
546         col = stck.col;
547 }