3 * Purpose: Implementation of insets for mathed
4 * Author: Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 * Created: January 1996
8 * Dependencies: Xlib, XForms
10 * Copyright: (c) 1996, Alejandro Aguilar Sierra
14 * You are free to use and modify this code under the terms of
15 * the GNU General Public Licence version 2 or later.
21 #pragma implementation "math_iter.h"
24 #include "math_iter.h"
25 #include "math_inset.h"
26 #include "symbol_def.h"
27 #include "support/lstrings.h"
30 const int SizeInset = sizeof(char*) + 2;
31 const int SizeFont = 2;
33 extern int mathed_char_width(short type, int style, byte c);
34 extern int mathed_string_width(short type, int style, byte const* s, int ls);
35 extern int mathed_char_height(short, int, byte, int&, int&);
37 // the builtin memcpy() is broken in egcs and gcc 2.95.x on alpha
38 // stations. We provide a hand-made version instead.
39 inline void my_memcpy( void* ps_in, const void* pt_in, unsigned int n )
41 char* ps = static_cast<char*>(ps_in);
42 char* pt = static_cast<char*>(const_cast<void*>(pt_in));
43 for( int i = 0; i < n; i++)
48 void MathedIter::Reset()
50 if (array->last>0 && MathIsFont(array->bf[0])) {
61 byte MathedIter::GetChar()
64 fcode = array->bf[pos];
67 return array->bf[pos];
71 byte* MathedIter::GetString(int& len)
74 fcode = array->bf[++pos];
77 byte *s = &array->bf[pos];
79 while (array->bf[pos]>= ' ' && pos<array->last) pos++;
85 MathedInset* MathedIter::GetInset()
89 my_memcpy(&p, &array->bf[pos+1], sizeof(p));
92 lyxerr << "Math Error: This is not an inset["
93 << array->bf[pos] << "]" << endl;
98 // An active math inset MUST be derived from MathParInset because it
99 // must have at least one paragraph to edit
100 MathParInset* MathedIter::GetActiveInset()
103 return (MathParInset*)GetInset();
106 lyxerr << "Math Error: This is not an active inset" << endl;
110 bool MathedIter::Next()
112 if (!OK()) return false;
114 if (array->bf[pos]<' ') {
124 pos += sizeof(char*) + 2;
129 fcode = array->bf[pos++];
136 bool MathedIter::goNextCode(MathedTextCodes code)
139 if (array->bf[pos] == code)
147 void MathedIter::goPosAbs(int p)
150 while (pos<p && Next());
154 void MathedIter::goPosRel(int dp)
158 // is posx a valid position?
161 while (pos<posx && Next());
165 void MathedIter::Insert(byte c, MathedTextCodes t)
169 if (t == LM_TC_TAB && col>= ncols-1)
172 // Never more than one space // array->bf[pos-1] gives error from purify:
173 // Reading 1 byte from 0x47b857 in the heap.
174 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
175 if (c == ' ' && (array->bf[pos] == ' ' || array->bf[pos-1] == ' '))
178 if (IsFont() && array->bf[pos] == t) {
182 if (t!= fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
185 for (k= pos-1; k>= 0 && array->bf[k]>= ' '; k--);
186 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
188 short f = (array->bf[pos]<' ') ? 0: fcode;
189 int shift = (t == fcode) ? 1: ((f) ? 3: 2);
191 if (t == LM_TC_TAB || t == LM_TC_CR) {
201 if (pos < array->last)
202 array->Move(pos, shift);
204 if (array->last+shift>= array->maxsize) {
205 array->Resize(array->last+shift);
207 array->last += shift;
208 array->bf[array->last] = '\0';
212 array->bf[pos+shift-1] = fcode;
214 array->bf[pos++] = t;
220 array->bf[pos++] = c;
224 // Prepare to insert a non-char object
225 void MathedIter::split(int shift)
227 if (pos < array->last) {
229 if (array->bf[pos]>= ' ') {
230 if (pos> 0 && MathIsFont(array->bf[pos-1]))
237 array->Move(pos, shift);
238 if (fg) array->bf[pos+shift-1] = fcode;
240 if (array->last+shift>= array->maxsize) {
241 array->Resize(array->last+shift);
243 array->last += shift;
245 array->bf[array->last] = '\0';
249 // I assume that both pos and pos2 are legal positions
250 void MathedIter::join(int pos2)
252 if (!OK() || pos2<= pos)
256 if (pos>0 && array->bf[pos]>= ' ' && MathIsFont(array->bf[pos-1]))
259 if (MathIsFont(array->bf[pos2-1]))
262 if (array->bf[pos2]>= ' ') {
263 for (int p= pos2; p>0; p--)
264 if (MathIsFont(array->bf[p])) {
268 array->bf[pos++] = f;
271 array->Move(pos2, pos-pos2);
274 void MathedIter::Insert(MathedInset* p, int type)
276 int shift = SizeInset;
277 if (!MathIsInset(type))
280 array->bf[pos] = type;
281 my_memcpy(&array->bf[pos+1], &p, sizeof(p));
283 array->bf[pos-1] = type;
284 array->bf[array->last] = '\0';
289 bool MathedIter::Delete()
297 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
301 for (i= pos-1; i>0 && !MathIsFont(array->bf[i]); i--);
302 if (i>0 && MathIsFont(array->bf[i]))
303 fcode = array->bf[i];
307 if (MathIsInset(array->bf[pos]))
308 shift = sizeof(char*) + 2;
310 if (c == LM_TC_TAB || c == LM_TC_CR) {
312 // lyxerr <<"Es un tab.";
315 lyxerr << "Math Warning: expected inset." << endl;
320 array->Move(pos+shift, -shift);
321 if (pos>= array->last)
322 pos = (array->last>0) ? array->last: 0;
329 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
332 // lyxerr << "Math error: Attempting to copy a void array." << endl;
338 LyxArrayBase *t= array, *a;
340 if (pos1>0 || pos2<= array->last) {
342 if (pos1>0 && array->bf[pos1]>' ') {
343 for (int p= pos1; p>= 0; p--)
344 if (MathIsFont(array->bf[p])) {
353 if (pos2>0 && array->bf[pos2]>= ' ' && MathIsFont(array->bf[pos2-1]))
356 int dx = pos2 - pos1;
357 a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
358 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
359 my_memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
367 a = new LyxArrayBase(*array);
371 MathedInset* inset = GetInset();
372 inset = inset->Clone();
373 my_memcpy(&array->bf[pos+1], &inset, sizeof(inset));
384 void MathedIter::Clear()
387 lyxerr << "Math error: Attempting to clean a void array." << endl;
393 MathedInset* inset = GetInset();
394 if (inset->GetType()!= LM_OT_MACRO_ARG)
403 // Check consistency of tabs and crs
404 void MathedIter::checkTabs()
408 // MathedIter:Reset();
410 if ((IsTab() && col>= ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
414 if (IsCR() && col<ncols-2) {
415 Insert(' ', LM_TC_TAB);
420 Insert(' ', LM_TC_TAB);
426 // Try to adjust tabs in the expected place, as used in eqnarrays
428 // - If there are a relation operator, put tabs around it
429 // - If tehre are not a relation operator, put everything in the
431 void MathedIter::adjustTabs()
437 void MathedXIter::Clean(int pos2)
440 lyxerr << "Math error: Attempting to clean a void array." << endl;
448 while (pos<pos2 && OK()) { Next();
455 while (OK() && pos<pos2) {
457 MathedInset* inset = GetInset();
459 if (inset->GetType()!= LM_OT_MACRO_ARG)
465 MathedRowSt *r = crow->next;
467 crow->next = r->next;
476 if (pos2<= array->Last()) {
484 void MathedXIter::Merge(LyxArrayBase *a0)
487 lyxerr[Debug::MATHED]
488 << "Math error: Attempting to merge a void array." << endl;
492 // All insets must be clonned
494 LyxArrayBase *a = it.Copy();
496 // make rom for the data
498 array->MergeF(a, pos, a->Last());
500 int pos1= pos, pos2 = pos + a->Last(); // pos3= 0;
505 while (pos<pos2 && OK()) {
507 if (p && p->Permit(LMPF_ALLOW_CR)) {
508 MathedRowSt *r = new MathedRowSt(ncols+1);
510 r->next = crow->next;
535 MathedXIter::MathedXIter(MathParInset* pp): p(pp)
549 void MathedXIter::SetData(MathParInset *pp)
553 array = p->GetData();
554 ncols = p->GetColumns();
555 crow = p->getRowSt();
556 if (p->Permit(LMPF_ALLOW_CR))
558 if (p->Permit(LMPF_ALLOW_TAB))
563 y = crow->getBaseline();
566 array = new LyxArrayBase; // this leaks
569 size = p->GetStyle();
573 byte* MathedXIter::GetString(int& ls)
576 byte const *sxs = MathedIter::GetString(ls);
578 strncpy(reinterpret_cast<char*>(s), reinterpret_cast<const char*>(sxs), ls);
579 x += mathed_string_width(fcode, size, s, ls);
586 bool MathedXIter::Next()
588 // lyxerr << "Ne[" << pos << "]";
589 if (!OK()) return false;
593 MathedInset* px = GetInset();
595 if (px->GetType() == LM_OT_SCRIPT) {
599 sx = (px->GetLimits()) ? w: 0;
603 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
604 w = mathed_char_width(fcode, size, c);
606 if (c == LM_TC_TAB && p) {
607 // w = p->GetTab(col+1);
608 w = (crow) ? crow->getTab(col+1): 0;
609 //lyxerr << "WW[" << w << "]";
611 if (c == LM_TC_CR && p) {
613 if (crow && crow->next) {
615 y = crow->getBaseline();
618 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
620 lyxerr << "No hubo w[" << c << "]!";
622 if (MathedIter::Next()) {
623 // lyxerr <<"LNX " << pos << endl;
624 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
625 // w = (sx>sw) ? 0: sw-sx;
626 if ((sw>0 || sx>0) && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
628 w = (sx>sw) ? 0: sw-sx;
638 void MathedXIter::GoBegin()
644 crow = p->getRowSt();
647 y = crow->getBaseline();
652 void MathedXIter::GoLast()
658 void MathedXIter::Adjust()
662 while (posx>pos && OK()) Next();
666 bool MathedXIter::Prev()
668 if (pos == 0 || (pos == 1 && GetChar()>= ' '))
671 int pos2 = pos; // pos1
683 bool MathedXIter::goNextColumn()
685 int rowp = row, colp= col;
686 while (Next() && col == colp);
688 return (col!= colp+1 || rowp!= row);
692 bool MathedXIter::Up()
694 if (row == 0) return false;
695 int xp = x, rowp = row, colp= col;
697 while (row<rowp-1) Next();
698 while (x<xp && OK() && !IsCR()) {
702 if (col>colp) // || (stck.col == colp && stck.x<= xp && x>xp))
709 bool MathedXIter::Down()
711 int xp = x, colp= col; // , rowp = row
713 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
717 while (x<xp && OK()) {
721 if (col>colp || (stck.col == colp && stck.x<= xp && x>xp))
729 void MathedXIter::addRow()
732 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
733 " line in a subparagraph. " << this << endl;
737 // Create new item for the structure
738 MathedRowSt *r = new MathedRowSt(ncols+1);
740 r->next = crow->next;
746 // Fill missed tabs in current row
748 Insert('T', LM_TC_TAB);
750 Insert('K', LM_TC_CR);
754 goNextCode(LM_TC_CR);
756 // Fill missed tabs in new row
758 Insert('T', LM_TC_TAB);
763 void MathedXIter::delRow()
766 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
769 bool line_empty = true;
775 } else if (!IsTab()) {
784 MathedRowSt *r = crow->next;
786 crow->next = r->next;
797 void MathedXIter::ipush()
805 void MathedXIter::ipop()
811 crow = p->getRowSt();
813 for (int i= 0; i<row; i++)
819 void MathedXIter::fitCoord(int /*xx*/, int yy)
826 // first fit vertically
827 while (crow && OK()) {
828 if (yy>= yo+y-crow->asc && yy<= yo+y+crow->desc)
830 goNextCode(LM_TC_CR);
834 // while (x<xx && Next());
837 void MathedXIter::setTab(int tx, int tab)
839 if (crow && tab<= ncols) {
843 lyxerr << "MathErr: No tabs allowed here" << endl;
847 void MathedXIter::subMetrics(int a, int d)
850 // lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
858 // This function is not recursive, as MathPar::Metrics is
859 void MathedXIter::IMetrics(int pos2, int& width, int& ascent, int& descent)
861 byte cx, cxp= 0;// *s;
866 descent = ascent = width = 0;
868 if (array->empty()) return;
869 // if (pos2 > array->last) return;
874 mathed_char_height(FCode(), size, cx, asc, des);
875 if (asc > ascent) ascent = asc;
876 if (des > descent) descent = des;
879 if (MathIsInset(cx)) {
880 MathedInset *pp = GetInset();
881 if (cx == LM_TC_UP) {
885 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
888 asc += ((limits) ? pp->Height()+4: pp->Ascent());
890 if (cx == LM_TC_DOWN) {
894 static_cast<MathParInset*>(pp)->GetXY(xx, des);
895 if (des-pp->Height()<yy && !asc)
896 asc = yy - (des-pp->Height());
899 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
904 if (asc > ascent) ascent = asc;
905 if (des > descent) descent = des;
906 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
907 limit = pp->GetLimits();
909 if (cx == LM_TC_TAB) {
913 lyxerr[Debug::MATHED]
914 << "Mathed Sel-Error: Unrecognized code["
915 << cx << ']' << endl;
918 if (pos < pos2) Next();
925 bool MathedXIter::setNumbered(bool numb)
928 crow->setNumbered(numb);
936 bool MathedXIter::setLabel(char* label)
939 crow->setLabel(label);
947 MathedRowSt *MathedXIter::adjustVerticalSt()
951 // lyxerr << " CRW" << ncols << " ";
952 crow = new MathedRowSt(ncols+1); // this leaks
954 // lyxerr<< " CRW[" << crow << "] ";
955 MathedRowSt *mrow = crow;
958 if (col>= ncols) ncols = col+1;
959 MathedRowSt *r = new MathedRowSt(ncols+1); // this leaks
960 // r->next = crow->next;
963 // lyxerr << " CX[" << crow << "]";