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