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, void const * 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 const * s = GetString(ls);
94 return string(reinterpret_cast<char const *>(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)
169 int const posx = pos + 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 >= 0 && array->bf[k] >= ' '; --k);
199 fcode = (k >= 0 && MathIsFont(array->bf[k])) ? array->bf[k] : -1;
201 short const 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 const 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 > 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;
322 else if (c == LM_TC_TAB || c == LM_TC_CR) {
324 // lyxerr <<"Es un tab.";
326 lyxerr << "Math Warning: expected inset." << endl;
331 array->Move(pos + shift, -shift);
332 if (pos >= array->last)
333 pos = (array->last > 0) ? array->last : 0;
340 LyxArrayBase * MathedIter::Copy(int pos1, int pos2)
343 // lyxerr << "Math error: Attempting to copy a void array." << endl;
349 LyxArrayBase * t = array, * a;
351 if (pos1 > 0 || pos2 <= array->last) {
353 if (pos1 > 0 && array->bf[pos1] > ' ') {
354 for (int p = pos1; p >= 0; --p)
355 if (MathIsFont(array->bf[p])) {
364 if (pos2 > 0 && array->bf[pos2] >= ' '
365 && MathIsFont(array->bf[pos2 - 1]))
368 int dx = pos2 - pos1;
369 a = new LyxArrayBase(dx + LyxArrayBase::ARRAY_MIN_SIZE);
370 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
371 my_memcpy(&a->bf[(fc) ? 1 : 0], &array->bf[pos1], dx);
379 a = new LyxArrayBase(*array);
383 MathedInset * inset = GetInset();
384 inset = inset->Clone();
385 my_memcpy(&array->bf[pos + 1], &inset, sizeof(inset));
396 void MathedIter::Clear()
399 lyxerr << "Math error: Attempting to clean a void array." << endl;
405 MathedInset * inset = GetInset();
406 if (inset->GetType()!= LM_OT_MACRO_ARG)
415 // Check consistency of tabs and crs
416 void MathedIter::checkTabs()
420 // MathedIter:Reset();
422 if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
426 if (IsCR() && col < ncols - 2) {
427 Insert(' ', LM_TC_TAB);
431 if (col < ncols - 2) {
432 Insert(' ', LM_TC_TAB);
438 // Try to adjust tabs in the expected place, as used in eqnarrays
440 // - If there are a relation operator, put tabs around it
441 // - If tehre are not a relation operator, put everything in the
443 void MathedIter::adjustTabs()
449 void MathedXIter::Clean(int pos2)
452 lyxerr << "Math error: Attempting to clean a void array." << endl;
460 while (pos < pos2 && OK()) {
468 while (OK() && pos < pos2) {
470 MathedInset * inset = GetInset();
472 if (inset->GetType()!= LM_OT_MACRO_ARG)
478 MathedRowSt * r = crow->getNext();
480 crow->setNext(r->getNext());
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 room for the data
511 array->MergeF(a, pos, a->Last());
514 int pos2 = pos + a->Last();
520 while (pos < pos2 && OK()) {
522 if (p && p->Permit(LMPF_ALLOW_CR)) {
523 MathedRowSt * r = new MathedRowSt(ncols+1);
525 r->setNext(crow->getNext());
550 MathedXIter::MathedXIter(MathParInset * pp)
565 void MathedXIter::SetData(MathParInset * pp)
569 array = p->GetData();
570 ncols = p->GetColumns();
571 crow = p->getRowSt();
572 if (p->Permit(LMPF_ALLOW_CR))
574 if (p->Permit(LMPF_ALLOW_TAB))
579 y = crow->getBaseline();
582 array = new LyxArrayBase; // this leaks
585 size = p->GetStyle();
590 byte * MathedXIter::GetString(int & ls) const
593 byte const * sxs = MathedIter::GetString(ls);
595 strncpy(reinterpret_cast<char*>(s),
596 reinterpret_cast<char const *>(sxs), ls);
597 x += mathed_string_width(fcode, size, s, ls);
604 string const MathedXIter::GetString() const
607 byte const * s = GetString(ls);
608 return string(reinterpret_cast<char const *>(s), ls);
612 bool MathedXIter::Next()
614 // lyxerr << "Ne[" << pos << "]";
615 if (!OK()) return false;
619 MathedInset * px = GetInset();
621 if (px->GetType() == LM_OT_SCRIPT) {
625 sx = (px->GetLimits()) ? w : 0;
629 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
630 w = mathed_char_width(fcode, size, c);
632 if (c == LM_TC_TAB && p) {
633 // w = p->GetTab(col + 1);
634 w = (crow) ? crow->getTab(col + 1) : 0;
635 //lyxerr << "WW[" << w << "]";
637 if (c == LM_TC_CR && p) {
639 if (crow && crow->getNext()) {
640 crow = crow->getNext();
641 y = crow->getBaseline();
644 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
646 lyxerr << "No hubo w[" << c << "]!";
648 if (MathedIter::Next()) {
649 // lyxerr <<"LNX " << pos << endl;
650 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
651 // w = (sx>sw) ? 0: sw-sx;
652 if ((sw > 0 || sx > 0)
653 && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
655 w = (sx > sw) ? 0 : sw - sx;
665 void MathedXIter::GoBegin()
671 crow = p->getRowSt();
674 y = crow->getBaseline();
679 void MathedXIter::GoLast()
685 void MathedXIter::Adjust()
689 while (posx > pos && OK()) Next();
693 bool MathedXIter::Prev()
695 if (pos == 0 || (pos == 1 && GetChar() >= ' '))
698 int pos2 = pos; // pos1
710 bool MathedXIter::goNextColumn()
714 while (Next() && col == colp);
716 return (col != colp + 1 || rowp != row);
720 bool MathedXIter::Up()
722 if (row == 0) return false;
727 while (row < rowp - 1) Next();
728 while (x < xp && OK() && !IsCR()) {
732 if (col > colp) // || (stck.col == colp && stck.x<= xp && x>xp))
739 bool MathedXIter::Down()
745 bool res = (IsCR()) ? true : goNextCode(LM_TC_CR);
749 while (x < xp && OK()) {
753 if (col > colp || (stck.col == colp && stck.x <= xp && x > xp))
761 void MathedXIter::addRow()
764 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
765 " line in a subparagraph. " << this << endl;
769 // Create new item for the structure
770 MathedRowSt * r = new MathedRowSt(ncols + 1);
772 r->setNext(crow->getNext());
778 // Fill missed tabs in current row
779 while (col < ncols - 1)
780 Insert('T', LM_TC_TAB);
782 Insert('K', LM_TC_CR);
786 goNextCode(LM_TC_CR);
788 // Fill missed tabs in new row
789 while (col < ncols - 1)
790 Insert('T', LM_TC_TAB);
795 void MathedXIter::delRow()
798 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
801 bool line_empty = true;
807 } else if (!IsTab()) {
811 int const p1 = getPos();
816 MathedRowSt * r = crow->getNext();
818 crow->setNext(r->getNext());
829 void MathedXIter::ipush()
837 void MathedXIter::ipop()
843 crow = p->getRowSt();
845 for (int i = 0; i < row; ++i)
846 crow = crow->getNext();
851 void MathedXIter::fitCoord(int /*xx*/, int yy)
859 // first fit vertically
860 while (crow && OK()) {
861 if (yy >= yo + y - crow->ascent() && yy <= yo + y + crow->descent())
863 goNextCode(LM_TC_CR);
867 // while (x<xx && Next());
871 void MathedXIter::setTab(int tx, int tab)
873 if (crow && tab <= ncols) {
874 crow->setTab(tab, tx);
876 lyxerr << "MathErr: No tabs allowed here" << endl;
880 void MathedXIter::subMetrics(int a, int d)
883 lyxerr[Debug::MATHED]
884 << "MathErr: Attempt to submetric a subparagraph." << endl;
892 // This function is not recursive, as MathPar::Metrics is
893 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
901 descent = ascent = width = 0;
903 if (array->empty()) return;
904 // if (pos2 > array->last) return;
909 mathed_char_height(FCode(), size, cx, asc, des);
910 if (asc > ascent) ascent = asc;
911 if (des > descent) descent = des;
914 if (MathIsInset(cx)) {
915 MathedInset * pp = GetInset();
916 if (cx == LM_TC_UP) {
921 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
924 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
925 } else if (cx == LM_TC_DOWN) {
930 static_cast<MathParInset*>(pp)->GetXY(xx, des);
931 if (des - pp->Height() < yy && !asc)
932 asc = yy - (des - pp->Height());
935 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
940 if (asc > ascent) ascent = asc;
941 if (des > descent) descent = des;
942 if (cx != LM_TC_UP && cx != LM_TC_DOWN)
943 limit = pp->GetLimits();
944 } else if (cx == LM_TC_TAB) {
947 lyxerr[Debug::MATHED]
948 << "Mathed Sel-Error: Unrecognized code["
949 << cx << ']' << endl;
952 if (pos < pos2) Next();
958 bool MathedXIter::setNumbered(bool numb)
961 crow->setNumbered(numb);
969 bool MathedXIter::setLabel(string const & label)
972 crow->setLabel(label);
980 MathedRowSt * MathedXIter::adjustVerticalSt()
984 // lyxerr << " CRW" << ncols << " ";
985 crow = new MathedRowSt(ncols + 1); // this leaks
987 // lyxerr<< " CRW[" << crow << "] ";
988 MathedRowSt * mrow = crow;
991 if (col >= ncols) ncols = col + 1;
992 MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
993 // r->next = crow->next;
996 // lyxerr << " CX[" << crow << "]";