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&);
38 void MathedIter::Reset()
40 if (array->last>0 && MathIsFont(array->bf[0])) {
51 byte MathedIter::GetChar()
54 fcode = array->bf[pos];
57 return array->bf[pos];
61 byte* MathedIter::GetString(int& len)
64 fcode = array->bf[++pos];
67 byte *s = &array->bf[pos];
69 while (array->bf[pos]>=' ' && pos<array->last) pos++;
75 MathedInset* MathedIter::GetInset()
79 memcpy(&p, &array->bf[pos+1], sizeof(p));
82 lyxerr << "Math Error: This is not an inset["
83 << array->bf[pos] << "]" << endl;
88 // An active math inset MUST be derived from MathParInset because it
89 // must have at least one paragraph to edit
90 MathParInset* MathedIter::GetActiveInset()
93 return (MathParInset*)GetInset();
96 lyxerr << "Math Error: This is not an active inset" << endl;
100 bool MathedIter::Next()
102 if (!OK()) return false;
104 if (array->bf[pos]<' ') {
114 pos += sizeof(char*) + 2;
119 fcode = array->bf[pos++];
126 bool MathedIter::goNextCode(MathedTextCodes code)
129 if (array->bf[pos]==code)
137 void MathedIter::goPosAbs(int p)
140 while (pos<p && Next());
144 void MathedIter::goPosRel(int dp)
148 // is posx a valid position?
151 while (pos<posx && Next());
155 void MathedIter::Insert(byte c, MathedTextCodes t)
159 if (t==LM_TC_TAB && col>=ncols-1)
162 // Never more than one space // array->bf[pos-1] gives error from purify:
163 // Reading 1 byte from 0x47b857 in the heap.
164 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
165 if (c==' ' && (array->bf[pos]==' ' || array->bf[pos-1]==' '))
168 if (IsFont() && array->bf[pos]==t) {
172 if (t!=fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
175 for (k=pos-1; k>=0 && array->bf[k]>=' '; k--);
176 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
178 short f = (array->bf[pos]<' ') ? 0: fcode;
179 int shift = (t==fcode) ? 1: ((f) ? 3: 2);
181 if (t==LM_TC_TAB || t==LM_TC_CR) {
191 if (pos < array->last)
192 array->Move(pos, shift);
194 if (array->last+shift>=array->maxsize) {
195 array->Resize(array->last+shift);
197 array->last += shift;
198 array->bf[array->last] = '\0';
202 array->bf[pos+shift-1] = fcode;
204 array->bf[pos++] = t;
210 array->bf[pos++] = c;
214 // Prepare to insert a non-char object
215 void MathedIter::split(int shift)
217 if (pos < array->last) {
219 if (array->bf[pos]>=' ') {
220 if (pos> 0 && MathIsFont(array->bf[pos-1]))
227 array->Move(pos, shift);
228 if (fg) array->bf[pos+shift-1] = fcode;
230 if (array->last+shift>=array->maxsize) {
231 array->Resize(array->last+shift);
233 array->last += shift;
235 array->bf[array->last] = '\0';
239 // I assume that both pos and pos2 are legal positions
240 void MathedIter::join(int pos2)
242 if (!OK() || pos2<=pos)
246 if (pos>0 && array->bf[pos]>=' ' && MathIsFont(array->bf[pos-1]))
249 if (MathIsFont(array->bf[pos2-1]))
252 if (array->bf[pos2]>=' ') {
253 for (int p=pos2; p>0; p--)
254 if (MathIsFont(array->bf[p])) {
258 array->bf[pos++] = f;
261 array->Move(pos2, pos-pos2);
264 void MathedIter::Insert(MathedInset* p, int type)
266 int shift = SizeInset;
267 if (!MathIsInset(type))
270 // array->bf[pos] = type;
271 // memcpy(&array->bf[pos+1], &p, sizeof(p));
273 // array->bf[pos-1] = type;
275 unsigned char *pt = &array->bf[pos];
276 unsigned char *ps = reinterpret_cast<unsigned char*>(&p);
279 for(i = 0; i < sizeof(p); i++) {
285 array->bf[array->last] = '\0';
290 bool MathedIter::Delete()
298 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
302 for (i=pos-1; i>0 && !MathIsFont(array->bf[i]); i--);
303 if (i>0 && MathIsFont(array->bf[i]))
304 fcode = array->bf[i];
308 if (MathIsInset(array->bf[pos]))
309 shift = sizeof(char*) + 2;
311 if (c==LM_TC_TAB || c==LM_TC_CR) {
313 // lyxerr <<"Es un tab.";
316 lyxerr << "Math Warning: expected inset." << endl;
321 array->Move(pos+shift, -shift);
322 if (pos>=array->last)
323 pos = (array->last>0) ? array->last: 0;
330 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
333 // lyxerr << "Math error: Attempting to copy a void array." << endl;
339 LyxArrayBase *t=array, *a;
341 if (pos1>0 || pos2<=array->last) {
343 if (pos1>0 && array->bf[pos1]>' ') {
344 for (int p=pos1; p>=0; p--)
345 if (MathIsFont(array->bf[p])) {
354 if (pos2>0 && array->bf[pos2]>=' ' && MathIsFont(array->bf[pos2-1]))
357 int dx = pos2 - pos1;
358 a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
359 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
360 memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
368 a = new LyxArrayBase(*array);
372 MathedInset* inset = GetInset();
373 inset = inset->Clone();
374 memcpy(&array->bf[pos+1], &inset, sizeof(inset));
385 void MathedIter::Clear()
388 lyxerr << "Math error: Attempting to clean a void array." << endl;
394 MathedInset* inset = GetInset();
395 if (inset->GetType()!=LM_OT_MACRO_ARG)
404 // Check consistency of tabs and crs
405 void MathedIter::checkTabs()
409 // MathedIter:Reset();
411 if ((IsTab() && col>=ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
415 if (IsCR() && col<ncols-2) {
416 Insert(' ', LM_TC_TAB);
421 Insert(' ', LM_TC_TAB);
427 // Try to adjust tabs in the expected place, as used in eqnarrays
429 // - If there are a relation operator, put tabs around it
430 // - If tehre are not a relation operator, put everything in the
432 void MathedIter::adjustTabs()
438 void MathedXIter::Clean(int pos2)
441 lyxerr << "Math error: Attempting to clean a void array." << endl;
449 while (pos<pos2 && OK()) { Next();
456 while (OK() && pos<pos2) {
458 MathedInset* inset = GetInset();
460 if (inset->GetType()!=LM_OT_MACRO_ARG)
466 MathedRowSt *r = crow->next;
468 crow->next = r->next;
477 if (pos2<=array->Last()) {
485 void MathedXIter::Merge(LyxArrayBase *a0)
488 lyxerr[Debug::MATHED]
489 << "Math error: Attempting to merge a void array." << endl;
493 // All insets must be clonned
495 LyxArrayBase *a = it.Copy();
497 // make rom for the data
499 array->MergeF(a, pos, a->Last());
501 int pos1=pos, pos2 = pos + a->Last(); // pos3=0;
506 while (pos<pos2 && OK()) {
508 if (p && p->Permit(LMPF_ALLOW_CR)) {
509 MathedRowSt *r = new MathedRowSt(ncols+1);
511 r->next = crow->next;
536 MathedXIter::MathedXIter(MathParInset* pp): p(pp)
550 void MathedXIter::SetData(MathParInset *pp)
554 array = p->GetData();
555 ncols = p->GetColumns();
556 crow = p->getRowSt();
557 if (p->Permit(LMPF_ALLOW_CR))
559 if (p->Permit(LMPF_ALLOW_TAB))
564 y = crow->getBaseline();
567 array = new LyxArrayBase; // this leaks
570 size = p->GetStyle();
574 byte* MathedXIter::GetString(int& ls)
577 byte const *sxs = MathedIter::GetString(ls);
579 strncpy(reinterpret_cast<char*>(s), reinterpret_cast<const char*>(sxs), ls);
580 x += mathed_string_width(fcode, size, s, ls);
587 bool MathedXIter::Next()
589 // lyxerr << "Ne[" << pos << "]";
590 if (!OK()) return false;
594 MathedInset* px = GetInset();
596 if (px->GetType()==LM_OT_SCRIPT) {
600 sx = (px->GetLimits()) ? w: 0;
604 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
605 w = mathed_char_width(fcode, size, c);
607 if (c==LM_TC_TAB && p) {
608 // w = p->GetTab(col+1);
609 w = (crow) ? crow->getTab(col+1): 0;
610 //lyxerr << "WW[" << w << "]";
612 if (c==LM_TC_CR && p) {
614 if (crow && crow->next) {
616 y = crow->getBaseline();
619 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
621 lyxerr << "No hubo w[" << c << "]!";
623 if (MathedIter::Next()) {
624 // lyxerr <<"LNX " << pos << endl;
625 // if (sw>0 && GetChar()!=LM_TC_UP && GetChar()!=LM_TC_DOWN) {
626 // w = (sx>sw) ? 0: sw-sx;
627 if ((sw>0 || sx>0) && GetChar()!=LM_TC_UP && GetChar()!=LM_TC_DOWN) {
629 w = (sx>sw) ? 0: sw-sx;
639 void MathedXIter::GoBegin()
645 crow = p->getRowSt();
648 y = crow->getBaseline();
653 void MathedXIter::GoLast()
659 void MathedXIter::Adjust()
663 while (posx>pos && OK()) Next();
667 bool MathedXIter::Prev()
669 if (pos==0 || (pos==1 && GetChar()>=' '))
672 int pos2 = pos; // pos1
684 bool MathedXIter::goNextColumn()
686 int rowp = row, colp=col;
687 while (Next() && col==colp);
689 return (col!=colp+1 || rowp!=row);
693 bool MathedXIter::Up()
695 if (row==0) return false;
696 int xp = x, rowp = row, colp=col;
698 while (row<rowp-1) Next();
699 while (x<xp && OK() && !IsCR()) {
703 if (col>colp) // || (stck.col==colp && stck.x<=xp && x>xp))
710 bool MathedXIter::Down()
712 int xp = x, colp=col; // ,rowp = row
714 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
718 while (x<xp && OK()) {
722 if (col>colp || (stck.col==colp && stck.x<=xp && x>xp))
730 void MathedXIter::addRow()
733 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
734 " line in a subparagraph. " << this << endl;
738 // Create new item for the structure
739 MathedRowSt *r = new MathedRowSt(ncols+1);
741 r->next = crow->next;
747 // Fill missed tabs in current row
749 Insert('T', LM_TC_TAB);
751 Insert('K', LM_TC_CR);
755 goNextCode(LM_TC_CR);
757 // Fill missed tabs in new row
759 Insert('T', LM_TC_TAB);
764 void MathedXIter::delRow()
767 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
770 bool line_empty = true;
776 } else if (!IsTab()) {
785 MathedRowSt *r = crow->next;
787 crow->next = r->next;
798 void MathedXIter::ipush()
806 void MathedXIter::ipop()
812 crow = p->getRowSt();
814 for (int i=0; i<row; i++)
820 void MathedXIter::fitCoord(int /*xx*/, int yy)
827 // first fit vertically
828 while (crow && OK()) {
829 if (yy>=yo+y-crow->asc && yy<= yo+y+crow->desc)
831 goNextCode(LM_TC_CR);
835 // while (x<xx && Next());
838 void MathedXIter::setTab(int tx, int tab)
840 if (crow && tab<=ncols) {
844 lyxerr << "MathErr: No tabs allowed here" << endl;
848 void MathedXIter::subMetrics(int a, int d)
851 // lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
859 // This function is not recursive, as MathPar::Metrics is
860 void MathedXIter::IMetrics(int pos2, int& width, int& ascent, int& descent)
862 byte cx, cxp=0;// *s;
867 descent = ascent = width = 0;
869 if (array->Empty()) return;
870 // if (pos2 > array->last) return;
875 mathed_char_height(FCode(), size, cx, asc, des);
876 if (asc > ascent) ascent = asc;
877 if (des > descent) descent = des;
880 if (MathIsInset(cx)) {
881 MathedInset *pp = GetInset();
886 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
889 asc += ((limits) ? pp->Height()+4: pp->Ascent());
891 if (cx==LM_TC_DOWN) {
895 static_cast<MathParInset*>(pp)->GetXY(xx, des);
896 if (des-pp->Height()<yy && !asc)
897 asc = yy - (des-pp->Height());
900 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
905 if (asc > ascent) ascent = asc;
906 if (des > descent) descent = des;
907 if (cx!=LM_TC_UP && cx!=LM_TC_DOWN)
908 limit = pp->GetLimits();
914 lyxerr[Debug::MATHED]
915 << "Mathed Sel-Error: Unrecognized code["
916 << cx << ']' << endl;
919 if (pos < pos2) Next();
926 bool MathedXIter::setNumbered(bool numb)
929 crow->setNumbered(numb);
937 bool MathedXIter::setLabel(char* label)
940 crow->setLabel(label);
948 MathedRowSt *MathedXIter::adjustVerticalSt()
952 // lyxerr << " CRW" << ncols << " ";
953 crow = new MathedRowSt(ncols+1); // this leaks
955 // lyxerr<< " CRW[" << crow << "] ";
956 MathedRowSt *mrow = crow;
959 if (col>=ncols) ncols = col+1;
960 MathedRowSt *r = new MathedRowSt(ncols+1); // this leaks
961 // r->next = crow->next;
964 // lyxerr << " CX[" << crow << "]";