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, string const & s);
36 extern int mathed_char_height(short, int, byte, int &, int &);
39 void MathedIter::Reset()
41 if (array->last() > 0 && MathIsFont((*array)[0])) {
52 byte MathedIter::GetChar() const
55 fcode = (*array)[pos];
62 string const MathedIter::GetString() const
65 fcode = (*array)[++pos];
69 for (; (*array)[pos] >= ' ' && pos < array->last(); ++pos)
76 MathedInset * MathedIter::GetInset() const
80 array->raw_pointer_copy(&p, pos + 1);
83 lyxerr << "Math Error: This is not an inset["
84 << (*array)[pos] << "]" << endl;
90 // An active math inset MUST be derived from MathParInset because it
91 // must have at least one paragraph to edit
92 MathParInset * MathedIter::GetActiveInset() const
95 return static_cast<MathParInset*>(GetInset());
98 lyxerr << "Math Error: This is not an active inset" << endl;
103 bool MathedIter::Next()
105 if (!OK()) return false;
107 if ((*array)[pos] < ' ') {
117 pos += sizeof(char*) + 2;
122 fcode = (*array)[pos++];
129 bool MathedIter::goNextCode(MathedTextCodes code)
132 if ((*array)[pos] == code)
140 void MathedIter::goPosAbs(int p)
143 while (pos < p && Next());
147 void MathedIter::goPosRel(int dp)
149 int const posx = pos + dp;
151 // is posx a valid position?
154 while (pos < posx && Next());
158 void MathedIter::Insert(byte c, MathedTextCodes t)
162 if (t == LM_TC_TAB && col >= ncols - 1)
165 // Never more than one space // array->bf[pos-1] gives error from purify:
166 // Reading 1 byte from 0x47b857 in the heap.
167 // Address 0x47b857 is 1 byte before start of malloc'd block at 0x47b858 of 16 bytes.
168 if (c == ' ' && ((*array)[pos] == ' ' || (*array)[pos - 1] == ' '))
171 if (IsFont() && (*array)[pos] == t) {
175 if (t != fcode && pos > 0 && MathIsFont((*array)[pos - 1])) {
178 for (; k >= 0 && (*array)[k] >= ' '; --k);
179 fcode = (k >= 0 && MathIsFont((*array)[k])) ? (*array)[k] : -1;
181 short const f = ((*array)[pos] < ' ') ? 0 : fcode;
182 int shift = (t == fcode) ? 1 : ((f) ? 3 : 2);
184 if (t == LM_TC_TAB || t == LM_TC_CR) {
194 if (pos < array->last())
195 array->move(pos, shift);
197 array->need_size(array->last() + shift);
198 array->last(array->last() + shift);
199 (*array)[array->last()] = '\0';
203 (*array)[pos + shift - 1] = fcode;
215 // Prepare to insert a non-char object
216 void MathedIter::split(int shift)
218 if (pos < array->last()) {
220 if ((*array)[pos] >= ' ') {
221 if (pos> 0 && MathIsFont((*array)[pos - 1]))
228 array->move(pos, shift);
229 if (fg) (*array)[pos + shift - 1] = fcode;
231 array->need_size(array->last() + shift);
232 array->last(array->last() + shift);
234 (*array)[array->last()] = '\0';
238 // I assume that both pos and pos2 are legal positions
239 void MathedIter::join(int pos2)
241 if (!OK() || pos2 <= pos)
245 if (pos > 0 && (*array)[pos] >= ' ' && MathIsFont((*array)[pos - 1]))
248 if (MathIsFont((*array)[pos2 - 1]))
251 if ((*array)[pos2] >= ' ') {
252 for (int p = pos2; p > 0; --p)
253 if (MathIsFont((*array)[p])) {
260 array->move(pos2, pos - pos2);
264 void MathedIter::Insert(MathedInset * p, int type)
266 int const shift = SizeInset;
267 if (!MathIsInset(type))
270 (*array)[pos] = type;
271 array->raw_pointer_insert(p, pos + 1, sizeof(p));
273 (*array)[pos - 1] = type;
274 (*array)[array->last()] = '\0';
279 bool MathedIter::Delete()
287 if (MathIsFont((*array)[pos - 1]) && (*array)[pos + 1] < ' ') {
291 for (; i > 0 && !MathIsFont((*array)[i]); --i);
292 if (i > 0 && MathIsFont((*array)[i]))
297 if (MathIsInset((*array)[pos]))
298 shift = sizeof(char*) + 2;
299 else if (c == LM_TC_TAB || c == LM_TC_CR) {
301 // lyxerr <<"Es un tab.";
303 lyxerr << "Math Warning: expected inset." << endl;
308 array->move(pos + shift, -shift);
309 if (pos >= array->last())
310 pos = (array->last() > 0) ? array->last() : 0;
317 MathedArray * MathedIter::Copy(int pos1, int pos2)
320 // lyxerr << "Math error: Attempting to copy a void array." << endl;
325 MathedArray * t = array;
328 if (pos1 > 0 || pos2 <= array->last()) {
330 if (pos1 > 0 && (*array)[pos1] > ' ') {
331 for (int p = pos1; p >= 0; --p)
332 if (MathIsFont((*array)[p])) {
341 if (pos2 > 0 && (*array)[pos2] >= ' '
342 && MathIsFont((*array)[pos2 - 1]))
345 int dx = pos2 - pos1;
346 a = new MathedArray(dx + MathedArray::ARRAY_MIN_SIZE);
347 // lyxerr << "VA " << pos2 << " " << pos2 << " " << dx << endl;
348 array->strange_copy(a, (fc) ? 1 : 0, pos1, dx);
356 a = new MathedArray(*array);
360 MathedInset * inset = GetInset();
361 inset = inset->Clone();
362 array->raw_pointer_insert(inset, pos + 1, sizeof(inset));
372 void MathedIter::Clear()
375 lyxerr << "Math error: Attempting to clean a void array." << endl;
381 MathedInset * inset = GetInset();
382 if (inset->GetType()!= LM_OT_MACRO_ARG)
391 // Check consistency of tabs and crs
392 void MathedIter::checkTabs()
396 // MathedIter:Reset();
398 if ((IsTab() && col >= ncols - 1) || (IsCR() && !(MthIF_CR & flags))) {
402 if (IsCR() && col < ncols - 2) {
403 Insert(' ', LM_TC_TAB);
407 if (col < ncols - 2) {
408 Insert(' ', LM_TC_TAB);
414 // Try to adjust tabs in the expected place, as used in eqnarrays
416 // - If there are a relation operator, put tabs around it
417 // - If tehre are not a relation operator, put everything in the
419 void MathedIter::adjustTabs()
425 void MathedXIter::Clean(int pos2)
428 lyxerr << "Math error: Attempting to clean a void array." << endl;
436 while (pos < pos2 && OK()) {
444 while (OK() && pos < pos2) {
446 MathedInset * inset = GetInset();
448 if (inset->GetType()!= LM_OT_MACRO_ARG)
454 MathedRowSt * r = crow->getNext();
456 crow->setNext(r->getNext());
465 if (pos2 <= array->last()) {
473 void MathedXIter::Merge(MathedArray * a0)
476 lyxerr[Debug::MATHED]
477 << "Math error: Attempting to merge a void array." << endl;
481 // All insets must be clonned
483 MathedArray * a = it.Copy();
485 // make room for the data
487 array->mergeF(a, pos, a->last());
490 int pos2 = pos + a->last();
495 while (pos < pos2 && OK()) {
497 if (p && p->Permit(LMPF_ALLOW_CR)) {
498 MathedRowSt * r = new MathedRowSt(ncols+1);
500 r->setNext(crow->getNext());
525 MathedXIter::MathedXIter(MathParInset * pp)
541 void MathedXIter::SetData(MathParInset * pp)
545 array = p->GetData();
546 ncols = p->GetColumns();
547 crow = p->getRowSt();
548 if (p->Permit(LMPF_ALLOW_CR))
550 if (p->Permit(LMPF_ALLOW_TAB))
555 y = crow->getBaseline();
558 array = new MathedArray; // this leaks
561 size = p->GetStyle();
566 string const MathedXIter::GetString() const
568 string s = MathedIter::GetString();
569 x += mathed_string_width(fcode, size, s);
574 bool MathedXIter::Next()
576 // lyxerr << "Ne[" << pos << "]";
577 if (!OK()) return false;
581 MathedInset * px = GetInset();
583 if (px->GetType() == LM_OT_SCRIPT) {
587 sx = (px->GetLimits()) ? w : 0;
591 // lyxerr << "WD[" << fcode << " " << size << " " << c << endl;
592 w = mathed_char_width(fcode, size, c);
594 if (c == LM_TC_TAB && p) {
595 // w = p->GetTab(col + 1);
596 w = (crow) ? crow->getTab(col + 1) : 0;
597 //lyxerr << "WW[" << w << "]";
599 if (c == LM_TC_CR && p) {
601 if (crow && crow->getNext()) {
602 crow = crow->getNext();
603 y = crow->getBaseline();
606 // lyxerr << "WW[" << col " " << row << "|" << w << "]";
608 lyxerr << "No hubo w[" << c << "]!";
610 if (MathedIter::Next()) {
611 // lyxerr <<"LNX " << pos << endl;
612 // if (sw>0 && GetChar()!= LM_TC_UP && GetChar()!= LM_TC_DOWN) {
613 // w = (sx>sw) ? 0: sw-sx;
614 if ((sw > 0 || sx > 0)
615 && GetChar() != LM_TC_UP && GetChar() != LM_TC_DOWN) {
617 w = (sx > sw) ? 0 : sw - sx;
627 void MathedXIter::GoBegin()
633 crow = p->getRowSt();
636 y = crow->getBaseline();
642 void MathedXIter::GoLast()
648 void MathedXIter::Adjust()
652 while (posx > pos && OK()) Next();
656 bool MathedXIter::Prev()
658 if (pos == 0 || (pos == 1 && GetChar() >= ' '))
661 int pos2 = pos; // pos1
673 bool MathedXIter::goNextColumn()
677 while (Next() && col == colp);
679 return (col != colp + 1 || rowp != row);
683 bool MathedXIter::Up()
685 if (row == 0) return false;
690 while (row < rowp - 1) Next();
691 while (x < xp && OK() && !IsCR()) {
695 if (col > colp) // || (stck.col == colp && stck.x<= xp && x>xp))
702 bool MathedXIter::Down()
708 bool res = (IsCR()) ? true : goNextCode(LM_TC_CR);
712 while (x < xp && OK()) {
716 if (col > colp || (stck.col == colp && stck.x <= xp && x > xp))
724 void MathedXIter::addRow()
727 lyxerr[Debug::MATHED] << "MathErr: Attempt to insert new"
728 " line in a subparagraph. " << this << endl;
732 // Create new item for the structure
733 MathedRowSt * r = new MathedRowSt(ncols + 1);
735 r->setNext(crow->getNext());
741 // Fill missed tabs in current row
742 while (col < ncols - 1)
743 Insert('T', LM_TC_TAB);
745 Insert('K', LM_TC_CR);
749 goNextCode(LM_TC_CR);
751 // Fill missed tabs in new row
752 while (col < ncols - 1)
753 Insert('T', LM_TC_TAB);
758 void MathedXIter::delRow()
761 lyxerr[Debug::MATHED] << "MathErr: Attempt to delete a line in a subparagraph." << endl;
764 bool line_empty = true;
770 } else if (!IsTab()) {
774 int const p1 = getPos();
779 MathedRowSt * r = crow->getNext();
781 crow->setNext(r->getNext());
793 void MathedXIter::ipush()
801 void MathedXIter::ipop()
807 crow = p->getRowSt();
809 for (int i = 0; i < row; ++i)
810 crow = crow->getNext();
815 void MathedXIter::fitCoord(int /*xx*/, int yy)
823 // first fit vertically
824 while (crow && OK()) {
825 if (yy >= yo + y - crow->ascent() && yy <= yo + y + crow->descent())
827 goNextCode(LM_TC_CR);
831 // while (x<xx && Next());
835 void MathedXIter::setTab(int tx, int tab)
837 if (crow && tab <= ncols) {
838 crow->setTab(tab, tx);
840 lyxerr << "MathErr: No tabs allowed here" << endl;
844 void MathedXIter::subMetrics(int a, int d)
847 lyxerr[Debug::MATHED]
848 << "MathErr: Attempt to submetric a subparagraph." << endl;
856 // This function is not recursive, as MathPar::Metrics is
857 void MathedXIter::IMetrics(int pos2, int & width, int & ascent, int & descent)
865 descent = ascent = width = 0;
867 if (array->empty()) return;
868 // if (pos2 > array->last) return;
873 mathed_char_height(FCode(), size, cx, asc, des);
874 if (asc > ascent) ascent = asc;
875 if (des > descent) descent = des;
878 if (MathIsInset(cx)) {
879 MathedInset * pp = GetInset();
880 if (cx == LM_TC_UP) {
885 static_cast<MathParInset*>(pp)->GetXY(xx, asc);
888 asc += ((limits) ? pp->Height() + 4 : pp->Ascent());
889 } else if (cx == LM_TC_DOWN) {
894 static_cast<MathParInset*>(pp)->GetXY(xx, des);
895 if (des - pp->Height() < yy && !asc)
896 asc = yy - (des - pp->Height());
899 des += (limit ? pp->Height()+4: pp->Height()-pp->Ascent()/2);
904 if (asc > ascent) ascent = asc;
905 if (des > descent) descent = des;
906 if (cx != LM_TC_UP && cx != LM_TC_DOWN)
907 limit = pp->GetLimits();
908 } else if (cx == LM_TC_TAB) {
911 lyxerr[Debug::MATHED]
912 << "Mathed Sel-Error: Unrecognized code["
913 << cx << ']' << endl;
916 if (pos < pos2) Next();
922 bool MathedXIter::setNumbered(bool numb)
925 crow->setNumbered(numb);
933 bool MathedXIter::setLabel(string const & label)
936 crow->setLabel(label);
944 MathedRowSt * MathedXIter::adjustVerticalSt()
948 // lyxerr << " CRW" << ncols << " ";
949 crow = new MathedRowSt(ncols + 1); // this leaks
951 // lyxerr<< " CRW[" << crow << "] ";
952 MathedRowSt * mrow = crow;
955 if (col >= ncols) ncols = col + 1;
956 MathedRowSt * r = new MathedRowSt(ncols + 1); // this leaks
957 // r->next = crow->next;
960 // lyxerr << " CX[" << crow << "]";
967 string MathedXIter::error_label = "$mathed-error$";