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: 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"
32 const int SizeInset = sizeof(char*) + 2;
34 extern int mathed_char_width(short type, int style, byte c);
35 extern int mathed_string_width(short type, int style, byte const* s, int ls);
36 extern int mathed_char_height(short, int, byte, int&, int&);
38 // the builtin memcpy() is broken in egcs and gcc 2.95.x on alpha
39 // stations. We provide a hand-made version instead.
41 void my_memcpy( void * ps_in, const void * pt_in, size_t n )
43 char * ps = static_cast<char *>(ps_in);
44 char const * pt = static_cast<char const *>(pt_in);
46 for (size_t i = n; i--;)
49 while (n--) *ps++ = *pt++;
53 void MathedIter::Reset()
55 if (array->last > 0 && MathIsFont(array->bf[0])) {
66 byte MathedIter::GetChar() const
69 fcode = array->bf[pos];
72 return array->bf[pos];
76 byte * MathedIter::GetString(int& len) const
79 fcode = array->bf[++pos];
82 byte * s = &array->bf[pos];
84 while (array->bf[pos] >= ' ' && pos < array->last) ++pos;
90 string const MathedIter::GetString() const
93 byte * s = GetString(ls);
94 return string(reinterpret_cast<char *>(s), ls);
98 MathedInset * MathedIter::GetInset() const
102 my_memcpy(&p, &array->bf[pos + 1], sizeof(p));
105 lyxerr << "Math Error: This is not an inset["
106 << array->bf[pos] << "]" << endl;
111 // An active math inset MUST be derived from MathParInset because it
112 // must have at least one paragraph to edit
113 MathParInset * MathedIter::GetActiveInset() const
116 return static_cast<MathParInset*>(GetInset());
119 lyxerr << "Math Error: This is not an active inset" << endl;
123 bool MathedIter::Next()
125 if (!OK()) return false;
127 if (array->bf[pos]<' ') {
137 pos += sizeof(char*) + 2;
142 fcode = array->bf[pos++];
149 bool MathedIter::goNextCode(MathedTextCodes code)
152 if (array->bf[pos] == code)
160 void MathedIter::goPosAbs(int p)
163 while (pos<p && Next());
167 void MathedIter::goPosRel(int dp)
171 // is posx a valid position?
174 while (pos<posx && Next());
178 void MathedIter::Insert(byte c, MathedTextCodes t)
182 if (t == LM_TC_TAB && col>= ncols-1)
185 // Never more than one space // array->bf[pos-1] gives error from purify:
186 // Reading 1 byte from 0x47b857 in the heap.
187 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
188 if (c == ' ' && (array->bf[pos] == ' ' || array->bf[pos-1] == ' '))
191 if (IsFont() && array->bf[pos] == t) {
195 if (t!= fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
198 for (k= pos-1; k>= 0 && array->bf[k]>= ' '; k--);
199 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
201 short f = (array->bf[pos]<' ') ? 0: fcode;
202 int shift = (t == fcode) ? 1: ((f) ? 3: 2);
204 if (t == LM_TC_TAB || t == LM_TC_CR) {
214 if (pos < array->last)
215 array->Move(pos, shift);
217 if (array->last+shift>= array->maxsize) {
218 array->Resize(array->last+shift);
220 array->last += shift;
221 array->bf[array->last] = '\0';
225 array->bf[pos+shift-1] = fcode;
227 array->bf[pos++] = t;
233 array->bf[pos++] = c;
237 // Prepare to insert a non-char object
238 void MathedIter::split(int shift)
240 if (pos < array->last) {
242 if (array->bf[pos]>= ' ') {
243 if (pos> 0 && MathIsFont(array->bf[pos-1]))
250 array->Move(pos, shift);
251 if (fg) array->bf[pos+shift-1] = fcode;
253 if (array->last+shift>= array->maxsize) {
254 array->Resize(array->last+shift);
256 array->last += shift;
258 array->bf[array->last] = '\0';
262 // I assume that both pos and pos2 are legal positions
263 void MathedIter::join(int pos2)
265 if (!OK() || pos2<= pos)
269 if (pos>0 && array->bf[pos]>= ' ' && MathIsFont(array->bf[pos-1]))
272 if (MathIsFont(array->bf[pos2-1]))
275 if (array->bf[pos2]>= ' ') {
276 for (int p= pos2; p>0; p--)
277 if (MathIsFont(array->bf[p])) {
281 array->bf[pos++] = f;
284 array->Move(pos2, pos-pos2);
287 void MathedIter::Insert(MathedInset* p, int type)
289 int shift = SizeInset;
290 if (!MathIsInset(type))
293 array->bf[pos] = type;
294 my_memcpy(&array->bf[pos+1], &p, sizeof(p));
296 array->bf[pos-1] = type;
297 array->bf[array->last] = '\0';
302 bool MathedIter::Delete()
310 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
314 for (i= pos-1; i>0 && !MathIsFont(array->bf[i]); i--);
315 if (i>0 && MathIsFont(array->bf[i]))
316 fcode = array->bf[i];
320 if (MathIsInset(array->bf[pos]))
321 shift = sizeof(char*) + 2;
323 if (c == LM_TC_TAB || c == LM_TC_CR) {
325 // lyxerr <<"Es un tab.";
328 lyxerr << "Math Warning: expected inset." << endl;
333 array->Move(pos+shift, -shift);
334 if (pos>= array->last)
335 pos = (array->last>0) ? array->last: 0;
342 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
345 // lyxerr << "Math error: Attempting to copy a void array." << endl;
351 LyxArrayBase *t= array, *a;
353 if (pos1>0 || pos2<= array->last) {
355 if (pos1>0 && array->bf[pos1]>' ') {
356 for (int p= pos1; p>= 0; p--)
357 if (MathIsFont(array->bf[p])) {
366 if (pos2>0 && array->bf[pos2]>= ' ' && MathIsFont(array->bf[pos2-1]))
369 int dx = pos2 - pos1;
370 a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
371 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
372 my_memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
380 a = new LyxArrayBase(*array);
384 MathedInset* inset = GetInset();
385 inset = inset->Clone();
386 my_memcpy(&array->bf[pos+1], &inset, sizeof(inset));
397 void MathedIter::Clear()
400 lyxerr << "Math error: Attempting to clean a void array." << endl;
406 MathedInset* inset = GetInset();
407 if (inset->GetType()!= LM_OT_MACRO_ARG)
416 // Check consistency of tabs and crs
417 void MathedIter::checkTabs()
421 // MathedIter:Reset();
423 if ((IsTab() && col>= ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
427 if (IsCR() && col<ncols-2) {
428 Insert(' ', LM_TC_TAB);
433 Insert(' ', LM_TC_TAB);
439 // Try to adjust tabs in the expected place, as used in eqnarrays
441 // - If there are a relation operator, put tabs around it
442 // - If tehre are not a relation operator, put everything in the
444 void MathedIter::adjustTabs()
450 void MathedXIter::Clean(int pos2)
453 lyxerr << "Math error: Attempting to clean a void array." << endl;
461 while (pos<pos2 && OK()) { Next();
468 while (OK() && pos<pos2) {
470 MathedInset* inset = GetInset();
472 if (inset->GetType()!= LM_OT_MACRO_ARG)
478 MathedRowSt *r = crow->next;
480 crow->next = r->next;
489 if (pos2<= array->Last()) {
497 void MathedXIter::Merge(LyxArrayBase *a0)
500 lyxerr[Debug::MATHED]
501 << "Math error: Attempting to merge a void array." << endl;
505 // All insets must be clonned
507 LyxArrayBase *a = it.Copy();
509 // make rom for the data
511 array->MergeF(a, pos, a->Last());
513 int pos1= pos, pos2 = pos + a->Last(); // pos3= 0;
518 while (pos<pos2 && OK()) {
520 if (p && p->Permit(LMPF_ALLOW_CR)) {
521 MathedRowSt *r = new MathedRowSt(ncols+1);
523 r->next = crow->next;
548 MathedXIter::MathedXIter(MathParInset * pp)
563 void MathedXIter::SetData(MathParInset * pp)
567 array = p->GetData();
568 ncols = p->GetColumns();
569 crow = p->getRowSt();
570 if (p->Permit(LMPF_ALLOW_CR))
572 if (p->Permit(LMPF_ALLOW_TAB))
577 y = crow->getBaseline();
580 array = new LyxArrayBase; // this leaks
583 size = p->GetStyle();
588 byte * MathedXIter::GetString(int & ls) const
591 byte const * sxs = MathedIter::GetString(ls);
593 strncpy(reinterpret_cast<char*>(s),
594 reinterpret_cast<const char*>(sxs), ls);
595 x += mathed_string_width(fcode, size, s, ls);
602 string const MathedXIter::GetString() const
605 byte * s = GetString(ls);
606 return string(reinterpret_cast<char*>(s), ls);
610 bool MathedXIter::Next()
612 // lyxerr << "Ne[" << pos << "]";
613 if (!OK()) return false;
617 MathedInset * px = GetInset();
619 if (px->GetType() == LM_OT_SCRIPT) {
623 sx = (px->GetLimits()) ? w : 0;
627 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
628 w = mathed_char_width(fcode, size, c);
630 if (c == LM_TC_TAB && p) {
631 // w = p->GetTab(col+1);
632 w = (crow) ? crow->getTab(col + 1) : 0;
633 //lyxerr << "WW[" << w << "]";
635 if (c == LM_TC_CR && p) {
637 if (crow && crow->next) {
639 y = crow->getBaseline();
642 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
644 lyxerr << "No hubo w[" << c << "]!";
646 if (MathedIter::Next()) {
647 // lyxerr <<"LNX " << pos << endl;
648 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
649 // w = (sx>sw) ? 0: sw-sx;
650 if ((sw > 0 || sx > 0)
651 && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
653 w = (sx > sw) ? 0 : sw - sx;
663 void MathedXIter::GoBegin()
669 crow = p->getRowSt();
672 y = crow->getBaseline();
677 void MathedXIter::GoLast()
683 void MathedXIter::Adjust()
687 while (posx>pos && OK()) Next();
691 bool MathedXIter::Prev()
693 if (pos == 0 || (pos == 1 && GetChar()>= ' '))
696 int pos2 = pos; // pos1
708 bool MathedXIter::goNextColumn()
710 int rowp = row, colp= col;
711 while (Next() && col == colp);
713 return (col!= colp+1 || rowp!= row);
717 bool MathedXIter::Up()
719 if (row == 0) return false;
720 int xp = x, rowp = row, colp= col;
722 while (row<rowp-1) Next();
723 while (x<xp && OK() && !IsCR()) {
727 if (col>colp) // || (stck.col == colp && stck.x<= xp && x>xp))
734 bool MathedXIter::Down()
736 int xp = x, colp= col; // , rowp = row
738 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
742 while (x<xp && OK()) {
746 if (col>colp || (stck.col == colp && stck.x<= xp && x>xp))
754 void MathedXIter::addRow()
757 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
758 " line in a subparagraph. " << this << endl;
762 // Create new item for the structure
763 MathedRowSt *r = new MathedRowSt(ncols+1);
765 r->next = crow->next;
771 // Fill missed tabs in current row
773 Insert('T', LM_TC_TAB);
775 Insert('K', LM_TC_CR);
779 goNextCode(LM_TC_CR);
781 // Fill missed tabs in new row
783 Insert('T', LM_TC_TAB);
788 void MathedXIter::delRow()
791 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
794 bool line_empty = true;
800 } else if (!IsTab()) {
809 MathedRowSt *r = crow->next;
811 crow->next = r->next;
822 void MathedXIter::ipush()
830 void MathedXIter::ipop()
836 crow = p->getRowSt();
838 for (int i= 0; i<row; i++)
844 void MathedXIter::fitCoord(int /*xx*/, int yy)
852 // first fit vertically
853 while (crow && OK()) {
854 if (yy >= yo + y - crow->asc && yy <= yo + y + crow->desc)
856 goNextCode(LM_TC_CR);
860 // while (x<xx && Next());
864 void MathedXIter::setTab(int tx, int tab)
866 if (crow && tab<= ncols) {
870 lyxerr << "MathErr: No tabs allowed here" << endl;
874 void MathedXIter::subMetrics(int a, int d)
877 // lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
885 // This function is not recursive, as MathPar::Metrics is
886 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
894 descent = ascent = width = 0;
896 if (array->empty()) return;
897 // if (pos2 > array->last) return;
902 mathed_char_height(FCode(), size, cx, asc, des);
903 if (asc > ascent) ascent = asc;
904 if (des > descent) descent = des;
907 if (MathIsInset(cx)) {
908 MathedInset *pp = GetInset();
909 if (cx == LM_TC_UP) {
914 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
917 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
919 if (cx == LM_TC_DOWN) {
924 static_cast<MathParInset*>(pp)->GetXY(xx, des);
925 if (des - pp->Height() < yy && !asc)
926 asc = yy - (des - pp->Height());
929 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
934 if (asc > ascent) ascent = asc;
935 if (des > descent) descent = des;
936 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
937 limit = pp->GetLimits();
939 if (cx == LM_TC_TAB) {
943 lyxerr[Debug::MATHED]
944 << "Mathed Sel-Error: Unrecognized code["
945 << cx << ']' << endl;
948 if (pos < pos2) Next();
954 bool MathedXIter::setNumbered(bool numb)
957 crow->setNumbered(numb);
965 bool MathedXIter::setLabel(string const & label)
967 if (!label.empty() && crow) {
968 crow->setLabel(label);
976 MathedRowSt * MathedXIter::adjustVerticalSt()
980 // lyxerr << " CRW" << ncols << " ";
981 crow = new MathedRowSt(ncols + 1); // this leaks
983 // lyxerr<< " CRW[" << crow << "] ";
984 MathedRowSt * mrow = crow;
987 if (col >= ncols) ncols = col + 1;
988 MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
989 // r->next = crow->next;
992 // lyxerr << " CX[" << crow << "]";