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"
29 const int SizeInset = sizeof(char*) + 2;
30 const int SizeFont = 2;
32 extern int mathed_char_width(short type, int style, byte c);
33 extern int mathed_string_width(short type, int style, byte const* s, int ls);
34 extern int mathed_char_height(short, int, byte, int&, int&);
37 void MathedIter::Reset()
39 if (array->last>0 && MathIsFont(array->bf[0])) {
50 byte MathedIter::GetChar()
53 fcode = array->bf[pos];
56 return array->bf[pos];
60 byte* MathedIter::GetString(int& len)
63 fcode = array->bf[++pos];
66 byte *s = &array->bf[pos];
68 while (array->bf[pos]>=' ' && pos<array->last) pos++;
74 MathedInset* MathedIter::GetInset()
78 memcpy(&p, &array->bf[pos+1], sizeof(p));
81 fprintf(stderr,"Math Error: This is not an inset[%d]\n", array->bf[pos]);
86 // An active math inset MUST be derived from MathParInset because it
87 // must have at least one paragraph to edit
88 MathParInset* MathedIter::GetActiveInset()
91 return (MathParInset*)GetInset();
94 fprintf(stderr,"Math Error: This is not an active inset\n");
98 bool MathedIter::Next()
100 if (!OK()) return false;
102 if (array->bf[pos]<' ') {
112 pos += sizeof(char*) + 2;
117 fcode = array->bf[pos++];
124 bool MathedIter::goNextCode(MathedTextCodes code)
127 if (array->bf[pos]==code)
135 void MathedIter::goPosAbs(int p)
138 while (pos<p && Next());
142 void MathedIter::goPosRel(int dp)
146 // is posx a valid position?
149 while (pos<posx && Next());
153 void MathedIter::Insert(byte c, MathedTextCodes t)
157 if (t==LM_TC_TAB && col>=ncols-1)
160 // Never more than one space // array->bf[pos-1] gives error from purify:
161 // Reading 1 byte from 0x47b857 in the heap.
162 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
163 if (c==' ' && (array->bf[pos]==' ' || array->bf[pos-1]==' '))
166 if (IsFont() && array->bf[pos]==t) {
170 if (t!=fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
173 for (k=pos-1; k>=0 && array->bf[k]>=' '; k--);
174 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
176 short f = (array->bf[pos]<' ') ? 0: fcode;
177 int shift = (t==fcode) ? 1: ((f) ? 3: 2);
179 if (t==LM_TC_TAB || t==LM_TC_CR) {
189 if (pos < array->last)
190 array->Move(pos, shift);
192 if (array->last+shift>=array->maxsize) {
193 array->Resize(array->last+shift);
195 array->last += shift;
196 array->bf[array->last] = '\0';
200 array->bf[pos+shift-1] = fcode;
202 array->bf[pos++] = t;
208 array->bf[pos++] = c;
212 // Prepare to insert a non-char object
213 void MathedIter::split(int shift)
215 if (pos < array->last) {
217 if (array->bf[pos]>=' ') {
218 if (pos> 0 && MathIsFont(array->bf[pos-1]))
225 array->Move(pos, shift);
226 if (fg) array->bf[pos+shift-1] = fcode;
228 if (array->last+shift>=array->maxsize) {
229 array->Resize(array->last+shift);
231 array->last += shift;
233 array->bf[array->last] = '\0';
237 // I assume that both pos and pos2 are legal positions
238 void MathedIter::join(int pos2)
240 if (!OK() || pos2<=pos)
244 if (pos>0 && array->bf[pos]>=' ' && MathIsFont(array->bf[pos-1]))
247 if (MathIsFont(array->bf[pos2-1]))
250 if (array->bf[pos2]>=' ') {
251 for (int p=pos2; p>0; p--)
252 if (MathIsFont(array->bf[p])) {
256 array->bf[pos++] = f;
259 array->Move(pos2, pos-pos2);
262 void MathedIter::Insert(MathedInset* p, int type)
264 int shift = SizeInset;
265 if (!MathIsInset(type))
268 // array->bf[pos] = type;
269 // memcpy(&array->bf[pos+1], &p, sizeof(p));
271 // array->bf[pos-1] = type;
273 unsigned char *pt = &array->bf[pos];
274 unsigned char *ps = (unsigned char *)&p;
277 for(i = 0; i < sizeof(p); i++) {
283 array->bf[array->last] = '\0';
288 bool MathedIter::Delete()
296 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
300 for (i=pos-1; i>0 && !MathIsFont(array->bf[i]); i--);
301 if (i>0 && MathIsFont(array->bf[i]))
302 fcode = array->bf[i];
306 if (MathIsInset(array->bf[pos]))
307 shift = sizeof(char*) + 2;
309 if (c==LM_TC_TAB || c==LM_TC_CR) {
311 // fprintf(stderr, "Es un tab.");
314 fprintf(stderr, "Math Warning: expected inset.");
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 // fprintf(stderr, "Math error: Attempting to copy a void array.\n");
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 // fprintf(stderr, "VA %d %d %d ", pos1, pos2, dx); fflush(stderr);
359 memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
367 a = new LyxArrayBase(*array);
371 MathedInset* inset = GetInset();
372 inset = inset->Clone();
373 memcpy(&array->bf[pos+1], &inset, sizeof(inset));
384 void MathedIter::Clear()
387 fprintf(stderr, "Math error: Attempting to clean a void array.\n");
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 fprintf(stderr, "Math error: Attempting to clean a void array.\n");
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("Math error: Attempting to merge a void array.",
491 // All insets must be clonned
493 LyxArrayBase *a = it.Copy();
495 // make rom for the data
497 array->MergeF(a, pos, a->Last());
499 int pos1=pos, pos2 = pos + a->Last(); // pos3=0;
504 while (pos<pos2 && OK()) {
506 if (p && p->Permit(LMPF_ALLOW_CR)) {
507 MathedRowSt *r = new MathedRowSt(ncols+1);
509 r->next = crow->next;
534 MathedXIter::MathedXIter(MathParInset* pp): p(pp)
548 void MathedXIter::SetData(MathParInset *pp)
552 array = p->GetData();
553 ncols = p->GetColumns();
554 crow = p->getRowSt();
555 if (p->Permit(LMPF_ALLOW_CR))
557 if (p->Permit(LMPF_ALLOW_TAB))
562 y = crow->getBaseline();
565 array = new LyxArrayBase; // this leaks
568 size = p->GetStyle();
572 byte* MathedXIter::GetString(int& ls)
575 byte const *sx = MathedIter::GetString(ls);
577 strncpy((char *)s, (char const*)sx, ls);
578 x += mathed_string_width(fcode, size, s, ls);
585 bool MathedXIter::Next()
587 // fprintf(stderr, "Ne[%d]", pos);
588 if (!OK()) return false;
590 // fprintf(stderr, "xt ");
592 MathedInset* px = GetInset();
594 if (px->GetType()==LM_OT_SCRIPT) {
598 sx = (px->GetLimits()) ? w: 0;
602 // fprintf(stderr, "WD[%d %d %c] ", fcode, size, c); fflush(stderr);
603 w = mathed_char_width(fcode, size, c);
605 if (c==LM_TC_TAB && p) {
606 // w = p->GetTab(col+1);
607 w = (crow) ? crow->getTab(col+1): 0;
608 //fprintf(stderr, "WW[%d]", w);
610 if (c==LM_TC_CR && p) {
612 if (crow && crow->next) {
614 y = crow->getBaseline();
617 // fprintf(stderr, "WW[%d %d|%d]", col, row, w);
619 fprintf(stderr, "No hubo w[%d]!", (int)c);
621 if (MathedIter::Next()) {
622 // fprintf(stderr, "LNX %d ", pos); fflush(stderr);
623 // if (sw>0 && GetChar()!=LM_TC_UP && GetChar()!=LM_TC_DOWN) {
624 // w = (sx>sw) ? 0: sw-sx;
625 if ((sw>0 || sx>0) && GetChar()!=LM_TC_UP && GetChar()!=LM_TC_DOWN) {
627 w = (sx>sw) ? 0: sw-sx;
637 void MathedXIter::GoBegin()
643 crow = p->getRowSt();
646 y = crow->getBaseline();
651 void MathedXIter::GoLast()
657 void MathedXIter::Adjust()
661 while (posx>pos && OK()) Next();
665 bool MathedXIter::Prev()
667 if (pos==0 || (pos==1 && GetChar()>=' '))
670 int pos2 = pos; // pos1
682 bool MathedXIter::goNextColumn()
684 int rowp = row, colp=col;
685 while (Next() && col==colp);
687 return (col!=colp+1 || rowp!=row);
691 bool MathedXIter::Up()
693 if (row==0) return false;
694 int xp = x, rowp = row, colp=col;
696 while (row<rowp-1) Next();
697 while (x<xp && OK() && !IsCR()) {
701 if (col>colp) // || (stck.col==colp && stck.x<=xp && x>xp))
708 bool MathedXIter::Down()
710 int xp = x, colp=col; // ,rowp = row
712 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
716 while (x<xp && OK()) {
720 if (col>colp || (stck.col==colp && stck.x<=xp && x>xp))
728 void MathedXIter::addRow()
731 lyxerr.debug(LString("MathErr: Attempt to insert new"
732 " line in a subparagraph. ")
733 + long(this), Error::MATHED);
736 // Create new item for the structure
737 MathedRowSt *r = new MathedRowSt(ncols+1);
739 r->next = crow->next;
745 // Fill missed tabs in current row
747 Insert('T', LM_TC_TAB);
749 Insert('K', LM_TC_CR);
753 goNextCode(LM_TC_CR);
755 // Fill missed tabs in new row
757 Insert('T', LM_TC_TAB);
762 void MathedXIter::delRow()
765 lyxerr.debug("MathErr: Attempt to delete a line in a subparagraph.",
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 fprintf(stderr, "MathErr: No tabs allowed here");
847 void MathedXIter::subMetrics(int a, int d)
850 // fprintf(stderr, "MathErr: Attempt to submetric a subparagraph.");
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();
885 ((MathParInset*)pp)->GetXY(xx, asc);
888 asc += ((limits) ? pp->Height()+4: pp->Ascent());
890 if (cx==LM_TC_DOWN) {
894 ((MathParInset*)pp)->GetXY(xx, des);
895 if (des-pp->Height()<yy && !asc)
896 asc = yy - (des-pp->Height());
899 des += ((limits) ? 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 limits = pp->GetLimits();
913 lyxerr.debug(LString("Mathed Sel-Error: Unrecognized code[")
914 + int(cx) + ']', Error::MATHED);
917 if (pos<pos2) Next();
924 bool MathedXIter::setNumbered(bool numb)
927 crow->setNumbered(numb);
935 bool MathedXIter::setLabel(char* label)
938 crow->setLabel(label);
946 MathedRowSt *MathedXIter::adjustVerticalSt()
950 // fprintf(stderr, " CRW%d ", ncols);
951 crow = new MathedRowSt(ncols+1); // this leaks
953 // fprintf(stderr, " CRW[%p] ", crow);
954 MathedRowSt *row = crow;
957 if (col>=ncols) ncols = col+1;
958 MathedRowSt *r = new MathedRowSt(ncols+1); // this leaks
959 // r->next = crow->next;
962 // fprintf(stderr, " CX[%p]", crow);