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, size_t n )
41 char * ps = static_cast<char *>(ps_in);
42 char const * pt = static_cast<char const *>(pt_in);
44 for(size_t i = n; i--;)
47 while (n--) *ps++ = *pt++;
51 void MathedIter::Reset()
53 if (array->last > 0 && MathIsFont(array->bf[0])) {
64 byte MathedIter::GetChar()
67 fcode = array->bf[pos];
70 return array->bf[pos];
74 byte * MathedIter::GetString(int& len)
77 fcode = array->bf[++pos];
80 byte * s = &array->bf[pos];
82 while (array->bf[pos] >= ' ' && pos<array->last) ++pos;
88 MathedInset* MathedIter::GetInset()
92 my_memcpy(&p, &array->bf[pos+1], sizeof(p));
95 lyxerr << "Math Error: This is not an inset["
96 << array->bf[pos] << "]" << endl;
101 // An active math inset MUST be derived from MathParInset because it
102 // must have at least one paragraph to edit
103 MathParInset * MathedIter::GetActiveInset()
106 return static_cast<MathParInset*>(GetInset());
109 lyxerr << "Math Error: This is not an active inset" << endl;
113 bool MathedIter::Next()
115 if (!OK()) return false;
117 if (array->bf[pos]<' ') {
127 pos += sizeof(char*) + 2;
132 fcode = array->bf[pos++];
139 bool MathedIter::goNextCode(MathedTextCodes code)
142 if (array->bf[pos] == code)
150 void MathedIter::goPosAbs(int p)
153 while (pos<p && Next());
157 void MathedIter::goPosRel(int dp)
161 // is posx a valid position?
164 while (pos<posx && Next());
168 void MathedIter::Insert(byte c, MathedTextCodes t)
172 if (t == LM_TC_TAB && col>= ncols-1)
175 // Never more than one space // array->bf[pos-1] gives error from purify:
176 // Reading 1 byte from 0x47b857 in the heap.
177 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
178 if (c == ' ' && (array->bf[pos] == ' ' || array->bf[pos-1] == ' '))
181 if (IsFont() && array->bf[pos] == t) {
185 if (t!= fcode && pos>0 && MathIsFont(array->bf[pos-1])) {
188 for (; k >= 0 && array->bf[k]>= ' '; --k);
189 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k]: -1;
191 short f = (array->bf[pos]<' ') ? 0: fcode;
192 int shift = (t == fcode) ? 1: ((f) ? 3: 2);
194 if (t == LM_TC_TAB || t == LM_TC_CR) {
204 if (pos < array->last)
205 array->Move(pos, shift);
207 if (array->last+shift>= array->maxsize) {
208 array->Resize(array->last+shift);
210 array->last += shift;
211 array->bf[array->last] = '\0';
215 array->bf[pos+shift-1] = fcode;
217 array->bf[pos++] = t;
223 array->bf[pos++] = c;
227 // Prepare to insert a non-char object
228 void MathedIter::split(int shift)
230 if (pos < array->last) {
232 if (array->bf[pos]>= ' ') {
233 if (pos> 0 && MathIsFont(array->bf[pos-1]))
240 array->Move(pos, shift);
241 if (fg) array->bf[pos+shift-1] = fcode;
243 if (array->last+shift>= array->maxsize) {
244 array->Resize(array->last+shift);
246 array->last += shift;
248 array->bf[array->last] = '\0';
252 // I assume that both pos and pos2 are legal positions
253 void MathedIter::join(int pos2)
255 if (!OK() || pos2 <= pos)
259 if (pos > 0 && array->bf[pos] >= ' ' && MathIsFont(array->bf[pos-1]))
262 if (MathIsFont(array->bf[pos2-1]))
265 if (array->bf[pos2] >= ' ') {
266 for (int p = pos2; p > 0; --p)
267 if (MathIsFont(array->bf[p])) {
271 array->bf[pos++] = f;
274 array->Move(pos2, pos-pos2);
277 void MathedIter::Insert(MathedInset* p, int type)
279 int shift = SizeInset;
280 if (!MathIsInset(type))
283 array->bf[pos] = type;
284 my_memcpy(&array->bf[pos+1], &p, sizeof(p));
286 array->bf[pos-1] = type;
287 array->bf[array->last] = '\0';
292 bool MathedIter::Delete()
300 if (MathIsFont(array->bf[pos-1]) && array->bf[pos+1]<' ') {
304 for (i = pos - 1; i > 0 && !MathIsFont(array->bf[i]); --i);
305 if (i>0 && MathIsFont(array->bf[i]))
306 fcode = array->bf[i];
310 if (MathIsInset(array->bf[pos]))
311 shift = sizeof(char*) + 2;
313 if (c == LM_TC_TAB || c == LM_TC_CR) {
315 // lyxerr <<"Es un tab.";
318 lyxerr << "Math Warning: expected inset." << endl;
323 array->Move(pos+shift, -shift);
324 if (pos>= array->last)
325 pos = (array->last>0) ? array->last: 0;
332 LyxArrayBase *MathedIter::Copy(int pos1, int pos2)
335 // lyxerr << "Math error: Attempting to copy a void array." << endl;
341 LyxArrayBase * t = array, *a;
343 if (pos1 > 0 || pos2 <= array->last) {
345 if (pos1>0 && array->bf[pos1]>' ') {
346 for (int p = pos1; p >= 0; --p)
347 if (MathIsFont(array->bf[p])) {
356 if (pos2 > 0 && array->bf[pos2] >= ' '
357 && MathIsFont(array->bf[pos2-1]))
360 int dx = pos2 - pos1;
361 a = new LyxArrayBase(dx+LyxArrayBase::ARRAY_MIN_SIZE);
362 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
363 my_memcpy(&a->bf[(fc) ? 1: 0], &array->bf[pos1], dx);
371 a = new LyxArrayBase(*array);
375 MathedInset* inset = GetInset();
376 inset = inset->Clone();
377 my_memcpy(&array->bf[pos+1], &inset, sizeof(inset));
388 void MathedIter::Clear()
391 lyxerr << "Math error: Attempting to clean a void array." << endl;
397 MathedInset * inset = GetInset();
398 if (inset->GetType()!= LM_OT_MACRO_ARG)
407 // Check consistency of tabs and crs
408 void MathedIter::checkTabs()
412 // MathedIter:Reset();
414 if ((IsTab() && col>= ncols-1) || (IsCR() && !(MthIF_CR&flags))) {
418 if (IsCR() && col<ncols-2) {
419 Insert(' ', LM_TC_TAB);
424 Insert(' ', LM_TC_TAB);
430 // Try to adjust tabs in the expected place, as used in eqnarrays
432 // - If there are a relation operator, put tabs around it
433 // - If tehre are not a relation operator, put everything in the
435 void MathedIter::adjustTabs()
441 void MathedXIter::Clean(int pos2)
444 lyxerr << "Math error: Attempting to clean a void array." << endl;
452 while (pos<pos2 && OK()) { Next();
459 while (OK() && pos<pos2) {
461 MathedInset* inset = GetInset();
463 if (inset->GetType()!= LM_OT_MACRO_ARG)
469 MathedRowSt *r = crow->next;
471 crow->next = r->next;
480 if (pos2<= array->Last()) {
488 void MathedXIter::Merge(LyxArrayBase *a0)
491 lyxerr[Debug::MATHED]
492 << "Math error: Attempting to merge a void array." << endl;
496 // All insets must be clonned
498 LyxArrayBase *a = it.Copy();
500 // make rom for the data
502 array->MergeF(a, pos, a->Last());
504 int pos1= pos, pos2 = pos + a->Last(); // pos3= 0;
509 while (pos<pos2 && OK()) {
511 if (p && p->Permit(LMPF_ALLOW_CR)) {
512 MathedRowSt *r = new MathedRowSt(ncols+1);
514 r->next = crow->next;
539 MathedXIter::MathedXIter(MathParInset* pp): p(pp)
553 void MathedXIter::SetData(MathParInset *pp)
557 array = p->GetData();
558 ncols = p->GetColumns();
559 crow = p->getRowSt();
560 if (p->Permit(LMPF_ALLOW_CR))
562 if (p->Permit(LMPF_ALLOW_TAB))
567 y = crow->getBaseline();
570 array = new LyxArrayBase; // this leaks
573 size = p->GetStyle();
577 byte* MathedXIter::GetString(int& ls)
580 byte const *sxs = MathedIter::GetString(ls);
582 strncpy(reinterpret_cast<char*>(s), reinterpret_cast<const char*>(sxs), ls);
583 x += mathed_string_width(fcode, size, s, ls);
590 bool MathedXIter::Next()
592 // lyxerr << "Ne[" << pos << "]";
593 if (!OK()) return false;
597 MathedInset* px = GetInset();
599 if (px->GetType() == LM_OT_SCRIPT) {
603 sx = (px->GetLimits()) ? w: 0;
607 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
608 w = mathed_char_width(fcode, size, c);
610 if (c == LM_TC_TAB && p) {
611 // w = p->GetTab(col+1);
612 w = (crow) ? crow->getTab(col+1): 0;
613 //lyxerr << "WW[" << w << "]";
615 if (c == LM_TC_CR && p) {
617 if (crow && crow->next) {
619 y = crow->getBaseline();
622 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
624 lyxerr << "No hubo w[" << c << "]!";
626 if (MathedIter::Next()) {
627 // lyxerr <<"LNX " << pos << endl;
628 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
629 // w = (sx>sw) ? 0: sw-sx;
630 if ((sw>0 || sx>0) && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
632 w = (sx>sw) ? 0: sw-sx;
642 void MathedXIter::GoBegin()
648 crow = p->getRowSt();
651 y = crow->getBaseline();
656 void MathedXIter::GoLast()
662 void MathedXIter::Adjust()
666 while (posx>pos && OK()) Next();
670 bool MathedXIter::Prev()
672 if (pos == 0 || (pos == 1 && GetChar()>= ' '))
675 int pos2 = pos; // pos1
687 bool MathedXIter::goNextColumn()
689 int rowp = row, colp= col;
690 while (Next() && col == colp);
692 return (col!= colp+1 || rowp!= row);
696 bool MathedXIter::Up()
698 if (row == 0) return false;
699 int xp = x, rowp = row, colp= col;
701 while (row<rowp-1) Next();
702 while (x<xp && OK() && !IsCR()) {
706 if (col>colp) // || (stck.col == colp && stck.x<= xp && x>xp))
713 bool MathedXIter::Down()
715 int xp = x, colp= col; // , rowp = row
717 bool res = (IsCR()) ? true: goNextCode(LM_TC_CR);
721 while (x<xp && OK()) {
725 if (col>colp || (stck.col == colp && stck.x<= xp && x>xp))
733 void MathedXIter::addRow()
736 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
737 " line in a subparagraph. " << this << endl;
741 // Create new item for the structure
742 MathedRowSt *r = new MathedRowSt(ncols+1);
744 r->next = crow->next;
750 // Fill missed tabs in current row
752 Insert('T', LM_TC_TAB);
754 Insert('K', LM_TC_CR);
758 goNextCode(LM_TC_CR);
760 // Fill missed tabs in new row
762 Insert('T', LM_TC_TAB);
767 void MathedXIter::delRow()
770 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
773 bool line_empty = true;
779 } else if (!IsTab()) {
788 MathedRowSt *r = crow->next;
790 crow->next = r->next;
801 void MathedXIter::ipush()
809 void MathedXIter::ipop()
815 crow = p->getRowSt();
817 for (int i = 0; i < row; ++i)
823 void MathedXIter::fitCoord(int /*xx*/, int yy)
830 // first fit vertically
831 while (crow && OK()) {
832 if (yy>= yo+y-crow->asc && yy<= yo+y+crow->desc)
834 goNextCode(LM_TC_CR);
838 // while (x<xx && Next());
841 void MathedXIter::setTab(int tx, int tab)
843 if (crow && tab<= ncols) {
847 lyxerr << "MathErr: No tabs allowed here" << endl;
851 void MathedXIter::subMetrics(int a, int d)
854 // lyxerr << "MathErr: Attempt to submetric a subparagraph." << endl;
862 // This function is not recursive, as MathPar::Metrics is
863 void MathedXIter::IMetrics(int pos2, int& width, int& ascent, int& descent)
865 byte cx, cxp= 0;// *s;
870 descent = ascent = width = 0;
872 if (array->empty()) return;
873 // if (pos2 > array->last) return;
878 mathed_char_height(FCode(), size, cx, asc, des);
879 if (asc > ascent) ascent = asc;
880 if (des > descent) descent = des;
883 if (MathIsInset(cx)) {
884 MathedInset *pp = GetInset();
885 if (cx == LM_TC_UP) {
889 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
892 asc += ((limits) ? pp->Height()+4: pp->Ascent());
894 if (cx == LM_TC_DOWN) {
898 static_cast<MathParInset*>(pp)->GetXY(xx, des);
899 if (des-pp->Height()<yy && !asc)
900 asc = yy - (des-pp->Height());
903 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
908 if (asc > ascent) ascent = asc;
909 if (des > descent) descent = des;
910 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
911 limit = pp->GetLimits();
913 if (cx == LM_TC_TAB) {
917 lyxerr[Debug::MATHED]
918 << "Mathed Sel-Error: Unrecognized code["
919 << cx << ']' << endl;
922 if (pos < pos2) Next();
929 bool MathedXIter::setNumbered(bool numb)
932 crow->setNumbered(numb);
940 bool MathedXIter::setLabel(char* label)
943 crow->setLabel(label);
951 MathedRowSt *MathedXIter::adjustVerticalSt()
955 // lyxerr << " CRW" << ncols << " ";
956 crow = new MathedRowSt(ncols+1); // this leaks
958 // lyxerr<< " CRW[" << crow << "] ";
959 MathedRowSt *mrow = crow;
962 if (col>= ncols) ncols = col+1;
963 MathedRowSt *r = new MathedRowSt(ncols+1); // this leaks
964 // r->next = crow->next;
967 // lyxerr << " CX[" << crow << "]";