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;
33 const int SizeFont = 2;
35 extern int mathed_char_width(short type, int style, byte c);
36 extern int mathed_string_width(short type, int style, byte const* s, int ls);
37 extern int mathed_char_height(short, int, byte, int&, int&);
39 // the builtin memcpy() is broken in egcs and gcc 2.95.x on alpha
40 // stations. We provide a hand-made version instead.
42 void my_memcpy( void * ps_in, const void * pt_in, size_t n )
44 char * ps = static_cast<char *>(ps_in);
45 char const * pt = static_cast<char const *>(pt_in);
47 for(size_t i = n; i--;)
50 while (n--) *ps++ = *pt++;
54 void MathedIter::Reset()
56 if (array->last > 0 && MathIsFont(array->bf[0])) {
67 byte MathedIter::GetChar() const
70 fcode = array->bf[pos];
73 return array->bf[pos];
77 byte * MathedIter::GetString(int& len) const
80 fcode = array->bf[++pos];
83 byte * s = &array->bf[pos];
85 while (array->bf[pos] >= ' ' && pos < array->last) ++pos;
91 string const MathedIter::GetString() const
94 byte * s = GetString(ls);
95 return string(reinterpret_cast<char *>(s), ls);
99 MathedInset * MathedIter::GetInset() const
103 my_memcpy(&p, &array->bf[pos + 1], sizeof(p));
106 lyxerr << "Math Error: This is not an inset["
107 << array->bf[pos] << "]" << endl;
112 // An active math inset MUST be derived from MathParInset because it
113 // must have at least one paragraph to edit
114 MathParInset * MathedIter::GetActiveInset() const
117 return static_cast<MathParInset*>(GetInset());
120 lyxerr << "Math Error: This is not an active inset" << endl;
124 bool MathedIter::Next()
126 if (!OK()) return false;
128 if (array->bf[pos]<' ') {
138 pos += sizeof(char*) + 2;
143 fcode = array->bf[pos++];
150 bool MathedIter::goNextCode(MathedTextCodes code)
153 if (array->bf[pos] == code)
161 void MathedIter::goPosAbs(int p)
164 while (pos<p && Next());
168 void MathedIter::goPosRel(int dp)
172 // is posx a valid position?
175 while (pos<posx && Next());
179 void MathedIter::Insert(byte c, MathedTextCodes t)
183 if (t == LM_TC_TAB && col>= ncols-1)
186 // Never more than one space // array->bf[pos-1] gives error from purify:
187 // Reading 1 byte from 0x47b857 in the heap.
188 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
189 if (c == ' ' && (array->bf[pos] == ' ' || array->bf[pos-1] == ' '))
192 if (IsFont() && array->bf[pos] == t) {
196 if (t!= fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
199 for (k= pos-1; k>= 0 && array->bf[k]>= ' '; k--);
200 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
202 short f = (array->bf[pos]<' ') ? 0: fcode;
203 int shift = (t == fcode) ? 1: ((f) ? 3: 2);
205 if (t == LM_TC_TAB || t == LM_TC_CR) {
215 if (pos < array->last)
216 array->Move(pos, shift);
218 if (array->last+shift>= array->maxsize) {
219 array->Resize(array->last+shift);
221 array->last += shift;
222 array->bf[array->last] = '\0';
226 array->bf[pos+shift-1] = fcode;
228 array->bf[pos++] = t;
234 array->bf[pos++] = c;
238 // Prepare to insert a non-char object
239 void MathedIter::split(int shift)
241 if (pos < array->last) {
243 if (array->bf[pos]>= ' ') {
244 if (pos> 0 && MathIsFont(array->bf[pos-1]))
251 array->Move(pos, shift);
252 if (fg) array->bf[pos+shift-1] = fcode;
254 if (array->last+shift>= array->maxsize) {
255 array->Resize(array->last+shift);
257 array->last += shift;
259 array->bf[array->last] = '\0';
263 // I assume that both pos and pos2 are legal positions
264 void MathedIter::join(int pos2)
266 if (!OK() || pos2<= pos)
270 if (pos>0 && array->bf[pos]>= ' ' && MathIsFont(array->bf[pos-1]))
273 if (MathIsFont(array->bf[pos2-1]))
276 if (array->bf[pos2]>= ' ') {
277 for (int p= pos2; p>0; p--)
278 if (MathIsFont(array->bf[p])) {
282 array->bf[pos++] = f;
285 array->Move(pos2, pos-pos2);
288 void MathedIter::Insert(MathedInset* p, int type)
290 int shift = SizeInset;
291 if (!MathIsInset(type))
294 array->bf[pos] = type;
295 my_memcpy(&array->bf[pos+1], &p, sizeof(p));
297 array->bf[pos-1] = type;
298 array->bf[array->last] = '\0';
303 bool MathedIter::Delete()
311 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
315 for (i= pos-1; i>0 && !MathIsFont(array->bf[i]); i--);
316 if (i>0 && MathIsFont(array->bf[i]))
317 fcode = array->bf[i];
321 if (MathIsInset(array->bf[pos]))
322 shift = sizeof(char*) + 2;
324 if (c == LM_TC_TAB || c == LM_TC_CR) {
326 // lyxerr <<"Es un tab.";
329 lyxerr << "Math Warning: expected inset." << endl;
334 array->Move(pos+shift, -shift);
335 if (pos>= array->last)
336 pos = (array->last>0) ? array->last: 0;
343 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
346 // lyxerr << "Math error: Attempting to copy a void array." << endl;
352 LyxArrayBase *t= array, *a;
354 if (pos1>0 || pos2<= array->last) {
356 if (pos1>0 && array->bf[pos1]>' ') {
357 for (int p= pos1; p>= 0; p--)
358 if (MathIsFont(array->bf[p])) {
367 if (pos2>0 && array->bf[pos2]>= ' ' && MathIsFont(array->bf[pos2-1]))
370 int dx = pos2 - pos1;
371 a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
372 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
373 my_memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
381 a = new LyxArrayBase(*array);
385 MathedInset* inset = GetInset();
386 inset = inset->Clone();
387 my_memcpy(&array->bf[pos+1], &inset, sizeof(inset));
398 void MathedIter::Clear()
401 lyxerr << "Math error: Attempting to clean a void array." << endl;
407 MathedInset* inset = GetInset();
408 if (inset->GetType()!= LM_OT_MACRO_ARG)
417 // Check consistency of tabs and crs
418 void MathedIter::checkTabs()
422 // MathedIter:Reset();
424 if ((IsTab() && col>= ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
428 if (IsCR() && col<ncols-2) {
429 Insert(' ', LM_TC_TAB);
434 Insert(' ', LM_TC_TAB);
440 // Try to adjust tabs in the expected place, as used in eqnarrays
442 // - If there are a relation operator, put tabs around it
443 // - If tehre are not a relation operator, put everything in the
445 void MathedIter::adjustTabs()
451 void MathedXIter::Clean(int pos2)
454 lyxerr << "Math error: Attempting to clean a void array." << endl;
462 while (pos<pos2 && OK()) { Next();
469 while (OK() && pos<pos2) {
471 MathedInset* inset = GetInset();
473 if (inset->GetType()!= LM_OT_MACRO_ARG)
479 MathedRowSt *r = crow->next;
481 crow->next = r->next;
490 if (pos2<= array->Last()) {
498 void MathedXIter::Merge(LyxArrayBase *a0)
501 lyxerr[Debug::MATHED]
502 << "Math error: Attempting to merge a void array." << endl;
506 // All insets must be clonned
508 LyxArrayBase *a = it.Copy();
510 // make rom for the data
512 array->MergeF(a, pos, a->Last());
514 int pos1= pos, pos2 = pos + a->Last(); // pos3= 0;
519 while (pos<pos2 && OK()) {
521 if (p && p->Permit(LMPF_ALLOW_CR)) {
522 MathedRowSt *r = new MathedRowSt(ncols+1);
524 r->next = crow->next;
549 MathedXIter::MathedXIter(MathParInset * pp)
564 void MathedXIter::SetData(MathParInset * pp)
568 array = p->GetData();
569 ncols = p->GetColumns();
570 crow = p->getRowSt();
571 if (p->Permit(LMPF_ALLOW_CR))
573 if (p->Permit(LMPF_ALLOW_TAB))
578 y = crow->getBaseline();
581 array = new LyxArrayBase; // this leaks
584 size = p->GetStyle();
589 byte * MathedXIter::GetString(int & ls) const
592 byte const * sxs = MathedIter::GetString(ls);
594 strncpy(reinterpret_cast<char*>(s),
595 reinterpret_cast<const char*>(sxs), ls);
596 x += mathed_string_width(fcode, size, s, ls);
603 string const MathedXIter::GetString() const
606 byte * s = GetString(ls);
607 return string(reinterpret_cast<char*>(s), ls);
611 bool MathedXIter::Next()
613 // lyxerr << "Ne[" << pos << "]";
614 if (!OK()) return false;
618 MathedInset * px = GetInset();
620 if (px->GetType() == LM_OT_SCRIPT) {
624 sx = (px->GetLimits()) ? w : 0;
628 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
629 w = mathed_char_width(fcode, size, c);
631 if (c == LM_TC_TAB && p) {
632 // w = p->GetTab(col+1);
633 w = (crow) ? crow->getTab(col + 1) : 0;
634 //lyxerr << "WW[" << w << "]";
636 if (c == LM_TC_CR && p) {
638 if (crow && crow->next) {
640 y = crow->getBaseline();
643 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
645 lyxerr << "No hubo w[" << c << "]!";
647 if (MathedIter::Next()) {
648 // lyxerr <<"LNX " << pos << endl;
649 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
650 // w = (sx>sw) ? 0: sw-sx;
651 if ((sw > 0 || sx > 0)
652 && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
654 w = (sx > sw) ? 0 : sw - sx;
664 void MathedXIter::GoBegin()
670 crow = p->getRowSt();
673 y = crow->getBaseline();
678 void MathedXIter::GoLast()
684 void MathedXIter::Adjust()
688 while (posx>pos && OK()) Next();
692 bool MathedXIter::Prev()
694 if (pos == 0 || (pos == 1 && GetChar()>= ' '))
697 int pos2 = pos; // pos1
709 bool MathedXIter::goNextColumn()
711 int rowp = row, colp= col;
712 while (Next() && col == colp);
714 return (col!= colp+1 || rowp!= row);
718 bool MathedXIter::Up()
720 if (row == 0) return false;
721 int xp = x, rowp = row, colp= col;
723 while (row<rowp-1) Next();
724 while (x<xp && OK() && !IsCR()) {
728 if (col>colp) // || (stck.col == colp && stck.x<= xp && x>xp))
735 bool MathedXIter::Down()
737 int xp = x, colp= col; // , rowp = row
739 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
743 while (x<xp && OK()) {
747 if (col>colp || (stck.col == colp && stck.x<= xp && x>xp))
755 void MathedXIter::addRow()
758 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
759 " line in a subparagraph. " << this << endl;
763 // Create new item for the structure
764 MathedRowSt *r = new MathedRowSt(ncols+1);
766 r->next = crow->next;
772 // Fill missed tabs in current row
774 Insert('T', LM_TC_TAB);
776 Insert('K', LM_TC_CR);
780 goNextCode(LM_TC_CR);
782 // Fill missed tabs in new row
784 Insert('T', LM_TC_TAB);
789 void MathedXIter::delRow()
792 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
795 bool line_empty = true;
801 } else if (!IsTab()) {
810 MathedRowSt *r = crow->next;
812 crow->next = r->next;
823 void MathedXIter::ipush()
831 void MathedXIter::ipop()
837 crow = p->getRowSt();
839 for (int i= 0; i<row; i++)
845 void MathedXIter::fitCoord(int /*xx*/, int yy)
853 // first fit vertically
854 while (crow && OK()) {
855 if (yy >= yo + y - crow->asc && yy <= yo + y + crow->desc)
857 goNextCode(LM_TC_CR);
861 // while (x<xx && Next());
865 void MathedXIter::setTab(int tx, int tab)
867 if (crow && tab<= ncols) {
871 lyxerr << "MathErr: No tabs allowed here" << endl;
875 void MathedXIter::subMetrics(int a, int d)
878 // lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
886 // This function is not recursive, as MathPar::Metrics is
887 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
896 descent = ascent = width = 0;
898 if (array->empty()) return;
899 // if (pos2 > array->last) return;
904 mathed_char_height(FCode(), size, cx, asc, des);
905 if (asc > ascent) ascent = asc;
906 if (des > descent) descent = des;
909 if (MathIsInset(cx)) {
910 MathedInset *pp = GetInset();
911 if (cx == LM_TC_UP) {
916 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
919 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
921 if (cx == LM_TC_DOWN) {
926 static_cast<MathParInset*>(pp)->GetXY(xx, des);
927 if (des - pp->Height() < yy && !asc)
928 asc = yy - (des - pp->Height());
931 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
936 if (asc > ascent) ascent = asc;
937 if (des > descent) descent = des;
938 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
939 limit = pp->GetLimits();
941 if (cx == LM_TC_TAB) {
945 lyxerr[Debug::MATHED]
946 << "Mathed Sel-Error: Unrecognized code["
947 << cx << ']' << endl;
950 if (pos < pos2) Next();
957 bool MathedXIter::setNumbered(bool numb)
960 crow->setNumbered(numb);
968 bool MathedXIter::setLabel(string const & label)
970 if (!label.empty() && crow) {
971 crow->setLabel(label);
979 MathedRowSt * MathedXIter::adjustVerticalSt()
983 // lyxerr << " CRW" << ncols << " ";
984 crow = new MathedRowSt(ncols + 1); // this leaks
986 // lyxerr<< " CRW[" << crow << "] ";
987 MathedRowSt * mrow = crow;
990 if (col >= ncols) ncols = col + 1;
991 MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
992 // r->next = crow->next;
995 // lyxerr << " CX[" << crow << "]";