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