X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_cursor.C;h=36834e7612654ec9826a7aa0dd2ef95018f9a7f7;hb=06f9f0ea08ddcf13e99ea02cff21471aa2020c9e;hp=4153bf4ac0078befaa61bfc42dca3eaaa144cbbc;hpb=192625aa3a572fb8966cfba6b03782c93af4e0bb;p=lyx.git diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 4153bf4ac0..36834e7612 100644 --- a/src/mathed/math_cursor.C +++ b/src/mathed/math_cursor.C @@ -15,29 +15,31 @@ * the GNU General Public Licence version 2 or later. */ +#include +#include + #ifdef __GNUG__ #pragma implementation #endif -#include -#include -#include - #include "support/lstrings.h" #include "support/LAssert.h" #include "debug.h" #include "LColor.h" -#include "Painter.h" +#include "frontends/Painter.h" +#include "math_cursor.h" #include "formulabase.h" #include "math_arrayinset.h" #include "math_braceinset.h" +#include "math_boxinset.h" #include "math_casesinset.h" #include "math_charinset.h" -#include "math_cursor.h" #include "math_deliminset.h" #include "math_factory.h" #include "math_hullinset.h" #include "math_iterator.h" +#include "math_macroarg.h" +#include "math_macrotemplate.h" #include "math_mathmlstream.h" #include "math_parser.h" #include "math_replace.h" @@ -46,31 +48,63 @@ #include "math_specialcharinset.h" #include "math_support.h" +#include +#include + #define FILEDEBUG 0 using std::endl; using std::min; using std::max; using std::swap; -using std::isalnum; +using std::vector; +using std::ostringstream; namespace { struct Selection { + typedef MathInset::col_type col_type; + typedef MathInset::row_type row_type; + typedef MathInset::idx_type idx_type; + + Selection() + : data_(1, 1) + {} + + void region(MathCursorPos const & i1, MathCursorPos const & i2, + row_type & r1, row_type & r2, col_type & c1, col_type & c2) + { + MathInset * p = i1.par_; + c1 = p->col(i1.idx_); + c2 = p->col(i2.idx_); + if (c1 > c2) + swap(c1, c2); + r1 = p->row(i1.idx_); + r2 = p->row(i2.idx_); + if (r1 > r2) + swap(r1, r2); + } + void grab(MathCursor const & cursor) { - data_.clear(); MathCursorPos i1; MathCursorPos i2; - cursor.getSelection(i1, i2); - if (i1.idx_ == i2.idx_) - data_.push_back(MathArray(i1.cell(), i1.pos_, i2.pos_)); - else { - std::vector indices = - i1.par_->idxBetween(i1.idx_, i2.idx_); - for (MathInset::idx_type i = 0; i < indices.size(); ++i) - data_.push_back(i1.cell(indices[i])); + cursor.getSelection(i1, i2); + // shouldn'tt we assert on i1.par_ == i2.par_? + if (i1.idx_ == i2.idx_) { + data_ = MathGridInset(1, 1); + data_.cell(0) = MathArray(i1.cell(), i1.pos_, i2.pos_); + } else { + row_type r1, r2; + col_type c1, c2; + region(i1, i2, r1, r2, c1, c2); + data_ = MathGridInset(c2 - c1 + 1, r2 - r1 + 1); + for (row_type row = 0; row < data_.nrows(); ++row) + for (col_type col = 0; col < data_.ncols(); ++col) { + idx_type i = i1.par_->index(row + r1, col + c1); + data_.cell(data_.index(row, col)) = i1.par_->cell(i); + } } } @@ -78,39 +112,65 @@ struct Selection { MathCursorPos i1; MathCursorPos i2; - cursor.getSelection(i1, i2); + cursor.getSelection(i1, i2); if (i1.idx_ == i2.idx_) i1.cell().erase(i1.pos_, i2.pos_); else { - std::vector indices = - i1.par_->idxBetween(i1.idx_, i2.idx_); - for (unsigned i = 0; i < indices.size(); ++i) - i1.cell(indices[i]).erase(); + MathInset * p = i1.par_; + row_type r1, r2; + col_type c1, c2; + region(i1, i2, r1, r2, c1, c2); + for (row_type row = r1; row <= r2; ++row) + for (col_type col = c1; col <= c2; ++col) + p->cell(p->index(row, col)).erase(); } cursor.cursor() = i1; } void paste(MathCursor & cursor) const { - MathArray ar = glue(); - cursor.paste(ar); + if (data_.nargs() == 1) { + // single cell/part of cell + cursor.paste(data_.cell(0)); + } else { + // mulitple cells + idx_type idx; // index of upper left cell + MathGridInset * p = cursor.enclosingGrid(idx); + col_type const numcols = min(data_.ncols(), p->ncols() - p->col(idx)); + row_type const numrows = min(data_.nrows(), p->nrows() - p->row(idx)); + for (row_type row = 0; row < numrows; ++row) { + for (col_type col = 0; col < numcols; ++col) { + idx_type i = p->index(row + p->row(idx), col + p->col(idx)); + p->cell(i).push_back(data_.cell(data_.index(row, col))); + } + // append the left over horizontal cells to the last column + idx_type i = p->index(row + p->row(idx), p->ncols() - 1); + for (col_type col = numcols; col < data_.ncols(); ++col) + p->cell(i).push_back(data_.cell(data_.index(row, col))); + } + // append the left over vertical cells to the last _cell_ + idx_type i = p->nargs() - 1; + for (row_type row = numrows; row < data_.nrows(); ++row) + for (col_type col = 0; col < data_.ncols(); ++col) + p->cell(i).push_back(data_.cell(data_.index(row, col))); + } } // glues selection to one cell MathArray glue() const { MathArray ar; - for (unsigned i = 0; i < data_.size(); ++i) - ar.push_back(data_[i]); + for (unsigned i = 0; i < data_.nargs(); ++i) + ar.push_back(data_.cell(i)); return ar; } void clear() { - data_.clear(); + data_ = MathGridInset(1, 1); } - std::vector data_; + MathGridInset data_; }; @@ -122,7 +182,7 @@ Selection theSelection; MathCursor::MathCursor(InsetFormulaBase * formula, bool left) - : formula_(formula), lastcode_(LM_TC_VAR), selection_(false) + : formula_(formula), lastcode_(LM_TC_MIN), selection_(false) { left ? first() : last(); } @@ -153,11 +213,9 @@ void MathCursor::pushRight(MathAtom & t) bool MathCursor::popLeft() { - //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " left\n"; + //cerr << "Leaving atom to the left\n"; if (Cursor_.size() <= 1) return false; - if (par()->asScriptInset()) - par()->asScriptInset()->removeEmptyScripts(); Cursor_.pop_back(); return true; } @@ -168,8 +226,6 @@ bool MathCursor::popRight() //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n"; if (Cursor_.size() <= 1) return false; - if (par()->asScriptInset()) - par()->asScriptInset()->removeEmptyScripts(); Cursor_.pop_back(); posRight(); return true; @@ -194,16 +250,10 @@ bool MathCursor::popRight() #endif -UpdatableInset * MathCursor::asHyperActiveInset() const -{ - return par()->asHyperActiveInset(); -} - - bool MathCursor::isInside(MathInset const * p) const { - for (unsigned i = 0; i < Cursor_.size(); ++i) - if (Cursor_[i].par_ == p) + for (unsigned i = 0; i < Cursor_.size(); ++i) + if (Cursor_[i].par_ == p) return true; return false; } @@ -211,9 +261,6 @@ bool MathCursor::isInside(MathInset const * p) const bool MathCursor::openable(MathAtom const & t, bool sel) const { - if (t->isHyperActive()) - return true; - if (!t->isActive()) return false; @@ -254,19 +301,16 @@ bool MathCursor::left(bool sel) dump("Left 1"); if (inMacroMode()) { macroModeClose(); - lastcode_ = LM_TC_VAR; + lastcode_ = LM_TC_MIN; return true; } selHandle(sel); - lastcode_ = LM_TC_VAR; + lastcode_ = LM_TC_MIN; if (hasPrevAtom() && openable(prevAtom(), sel)) { - if (prevAtom()->isHyperActive()) { - lyxerr << "entering hyperactive inset\n"; - } pushRight(prevAtom()); return true; - } + } return posLeft() || idxLeft() || popLeft() || selection_; } @@ -277,19 +321,13 @@ bool MathCursor::right(bool sel) dump("Right 1"); if (inMacroMode()) { macroModeClose(); - lastcode_ = LM_TC_VAR; + lastcode_ = LM_TC_MIN; return true; } selHandle(sel); - lastcode_ = LM_TC_VAR; + lastcode_ = LM_TC_MIN; if (hasNextAtom() && openable(nextAtom(), sel)) { - if (nextAtom()->isHyperActive()) { - lyxerr << "entering hyperactive inset\n"; - int x, y; - getPos(x, y); - nextAtom()->edit(formula()->view(), x, y, 0); - } pushLeft(nextAtom()); return true; } @@ -313,7 +351,7 @@ void MathCursor::last() bool positionable(MathCursor::cursor_type const & cursor, - MathCursor::cursor_type const & anchor) + MathCursor::cursor_type const & anchor) { // avoid deeper nested insets when selecting if (cursor.size() > anchor.size()) @@ -331,11 +369,15 @@ bool positionable(MathCursor::cursor_type const & cursor, void MathCursor::setPos(int x, int y) { - dump("setPos 2"); + dump("setPos 1"); bool res = bruteFind(x, y, formula()->xlow(), formula()->xhigh(), formula()->ylow(), formula()->yhigh()); - lyx::Assert(res); + if (!res) { + // this ccan happen on creation of "math-display" + dump("setPos 1.5"); + first(); + } dump("setPos 2"); } @@ -346,8 +388,8 @@ void MathCursor::home(bool sel) dump("home 1"); selHandle(sel); macroModeClose(); - lastcode_ = LM_TC_VAR; - if (!par()->idxHome(idx(), pos())) + lastcode_ = LM_TC_MIN; + if (!par()->idxHome(idx(), pos())) popLeft(); dump("home 2"); } @@ -358,7 +400,7 @@ void MathCursor::end(bool sel) dump("end 1"); selHandle(sel); macroModeClose(); - lastcode_ = LM_TC_VAR; + lastcode_ = LM_TC_MIN; if (!par()->idxEnd(idx(), pos())) popRight(); dump("end 2"); @@ -371,6 +413,20 @@ void MathCursor::plainErase() } +void MathCursor::markInsert() +{ + //lyxerr << "inserting mark\n"; + array().insert(pos(), MathAtom(new MathCharInset(0, lastcode_))); +} + + +void MathCursor::markErase() +{ + //lyxerr << "deleting mark\n"; + array().erase(pos()); +} + + void MathCursor::plainInsert(MathAtom const & t) { array().insert(pos(), t); @@ -381,10 +437,17 @@ void MathCursor::plainInsert(MathAtom const & t) void MathCursor::insert(char c, MathTextCodes t) { //lyxerr << "inserting '" << c << "'\n"; + selClearOrDel(); plainInsert(MathAtom(new MathCharInset(c, t))); } +void MathCursor::insert(char c) +{ + insert(c, lastcode_); +} + + void MathCursor::insert(MathAtom const & t) { macroModeClose(); @@ -393,14 +456,14 @@ void MathCursor::insert(MathAtom const & t) if (t->nargs()) selCut(); else - selDel(); + selClearOrDel(); } plainInsert(t); } -void MathCursor::niceInsert(MathAtom const & t) +void MathCursor::niceInsert(MathAtom const & t) { selCut(); insert(t); // inserting invalidates the pointer! @@ -438,7 +501,7 @@ void MathCursor::backspace() if (pos() == 0) { pullArg(false); return; - } + } if (selection_) { selDel(); @@ -448,7 +511,7 @@ void MathCursor::backspace() MathScriptInset * p = prevAtom()->asScriptInset(); if (p) { p->removeScript(p->hasUp()); - // Don't delete if there is anything left + // Don't delete if there is anything left if (p->hasUp() || p->hasDown()) return; } @@ -468,23 +531,21 @@ void MathCursor::erase() return; } - // delete empty cells if necessary - if (array().empty()) { - bool popit; - bool removeit; - par()->idxDelete(idx(), popit, removeit); - if (popit && popLeft() && removeit) - plainErase(); - return; - } + // delete empty cells if possible + if (array().empty()) + if (par()->idxDelete(idx())) + return; - if (pos() == size()) + // old behaviour when in last position of cell + if (pos() == size()) { + par()->idxGlue(idx()); return; + } MathScriptInset * p = nextAtom()->asScriptInset(); if (p) { p->removeScript(p->hasUp()); - // Don't delete if there is anything left + // Don't delete if there is anything left if (p->hasUp() || p->hasDown()) return; } @@ -508,8 +569,8 @@ void MathCursor::delLine() par()->asGridInset()->delRow(hullRow()); } - if (idx() > par()->nargs()) - idx() = par()->nargs(); + if (idx() >= par()->nargs()) + idx() = par()->nargs() - 1; if (pos() > size()) pos() = size(); @@ -557,19 +618,20 @@ bool MathCursor::toggleLimits() void MathCursor::macroModeClose() { + MathInset::difference_type const t = macroNamePos(); + if (t == -1) + return; string s = macroName(); - if (s.size()) { - size_type old = pos(); - pos() -= s.size(); - array().erase(pos(), old); + array().erase(t, pos()); + pos() = t; + if (s != "\\") interpret(s); - } } -int MathCursor::macroNamePos() const +MathInset::difference_type MathCursor::macroNamePos() const { - for (int i = pos() - 1; i >= 0; --i) { + for (MathInset::difference_type i = pos() - 1; i >= 0; --i) { MathAtom & p = array().at(i); if (p->code() == LM_TC_TEX && p->getChar() == '\\') return i; @@ -581,7 +643,8 @@ int MathCursor::macroNamePos() const string MathCursor::macroName() const { string s; - for (int i = macroNamePos(); i >= 0 && i < int(pos()); ++i) + MathInset::difference_type i = macroNamePos(); + for (; i >= 0 && i < int(pos()); ++i) s += array().at(i)->getChar(); return s; } @@ -592,7 +655,7 @@ void MathCursor::selCopy() dump("selCopy"); if (selection_) { theSelection.grab(*this); - selClear(); + //selClear(); } } @@ -625,9 +688,10 @@ void MathCursor::selDel() void MathCursor::selPaste() { dump("selPaste"); + selClearOrDel(); theSelection.paste(*this); //theSelection.grab(*this); - //selClear(); + selClear(); } @@ -659,6 +723,15 @@ void MathCursor::selClear() } +void MathCursor::selClearOrDel() +{ + if (lyxrc.auto_region_delete) + selDel(); + else + selClear(); +} + + void MathCursor::selGet(MathArray & ar) { dump("selGet"); @@ -688,7 +761,7 @@ void MathCursor::drawSelection(Painter & pain) const int y2 = c.yo() + c.descent(); pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); } else { - std::vector indices + vector indices = i1.par_->idxBetween(i1.idx_, i2.idx_); for (unsigned i = 0; i < indices.size(); ++i) { MathXArray & c = i1.xcell(indices[i]); @@ -720,13 +793,13 @@ void MathCursor::handleFont(MathTextCodes t) if (selection_) { MathCursorPos i1; MathCursorPos i2; - getSelection(i1, i2); + getSelection(i1, i2); if (i1.idx_ == i2.idx_) { MathArray & ar = i1.cell(); for (MathInset::pos_type pos = i1.pos_; pos != i2.pos_; ++pos) ar.at(pos)->handleFont(t); } - } else + } else lastcode_ = (lastcode_ == t) ? LM_TC_VAR : t; } @@ -754,6 +827,9 @@ void MathCursor::getPos(int & x, int & y) #warning This should probably take cellXOffset and cellYOffset into account #endif x = xarray().xo() + xarray().pos2x(pos()); + // move cursor visually into empty cells ("blue rectangles"); + if (array().empty()) + x += 2; y = xarray().yo(); } @@ -800,6 +876,12 @@ bool MathCursor::inMacroMode() const } +bool MathCursor::inMacroArgMode() const +{ + return pos() > 0 && prevAtom()->getChar() == '#'; +} + + bool MathCursor::selection() const { return selection_; @@ -808,17 +890,25 @@ bool MathCursor::selection() const MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const { - for (int i = Cursor_.size() - 1; i >= 0; --i) { + for (MathInset::difference_type i = Cursor_.size() - 1; i >= 0; --i) { MathGridInset * p = Cursor_[i].par_->asGridInset(); if (p) { idx = Cursor_[i].idx_; return p; + lyxerr << "found grid and idx: " << idx << "\n"; } } return 0; } +void MathCursor::popToEnclosingGrid() +{ + while (Cursor_.size() && !Cursor_.back().par_->asGridInset()) + Cursor_.pop_back(); +} + + void MathCursor::pullArg(bool goright) { dump("pullarg"); @@ -840,36 +930,68 @@ void MathCursor::pullArg(bool goright) if (popLeft()) { plainErase(); array().insert(pos(), a); - if (goright) + if (goright) pos() += a.size(); + } else { + formula()->mutateToText(); } } -void MathCursor::normalize() const +void MathCursor::touch() { -#ifdef WITH_WARNINGS -#warning This is evil! + cursor_type::const_iterator it = Cursor_.begin(); + cursor_type::const_iterator et = Cursor_.end(); + for ( ; it != et; ++it) + it->xcell().touch(); +} + + +void MathCursor::normalize() +{ +#if 0 + // rebreak + { + MathIterator it = ibegin(formula()->par().nucleus()); + MathIterator et = iend(formula()->par().nucleus()); + for (; it != et; ++it) + if (it.par()->asBoxInset()) + it.par()->asBoxInset()->rebreak(); + } #endif - MathCursor * it = const_cast(this); - if (idx() >= par()->nargs()) { + if (idx() >= par()->nargs()) { lyxerr << "this should not really happen - 1: " << idx() << " " << par()->nargs() << "\n"; dump("error 2"); } - it->idx() = min(idx(), par()->nargs() - 1); + idx() = min(idx(), par()->nargs() - 1); if (pos() > size()) { lyxerr << "this should not really happen - 2: " - << pos() << " " << size() << " in idx: " << it->idx() + << pos() << " " << size() << " in idx: " << idx() << " in atom: '"; - WriteStream wi(lyxerr, false); - it->par()->write(wi); + WriteStream wi(lyxerr, false, true); + par()->write(wi); lyxerr << "\n"; dump("error 4"); } - it->pos() = min(pos(), size()); + pos() = min(pos(), size()); + + // remove empty scripts if possible + if (1) { + for (pos_type i = 0; i < size(); ++i) { + MathScriptInset * p = array().at(i)->asScriptInset(); + if (p) { + p->removeEmptyScripts(); + //if (p->empty()) + // array().erase(i); + } + } + } + + // fix again position + pos() = min(pos(), size()); } @@ -976,7 +1098,7 @@ void MathCursor::idxPrev() void MathCursor::splitCell() { - if (idx() + 1 == par()->nargs()) + if (idx() + 1 == par()->nargs()) return; MathArray ar = array(); ar.erase(0, pos()); @@ -1069,33 +1191,75 @@ MathCursorPos const & MathCursor::cursor() const bool MathCursor::goUpDown(bool up) { + // Be warned: The 'logic' implemented in this function is highly fragile. + // A distance of one pixel or a '<' vs '<=' _really_ matters. + // So fiddle around with it only if you know what you are doing! int xlow, xhigh, ylow, yhigh; int xo, yo; getPos(xo, yo); - // try current cell first - xarray().boundingBox(xlow, xhigh, ylow, yhigh); - if (up) - yhigh = yo - 4; - else - ylow = yo + 4; - if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) - return true; + // try neigbouring script insets + // try left + if (hasPrevAtom()) { + MathScriptInset * p = prevAtom()->asScriptInset(); + if (p && p->has(up)) { + --pos(); + push(nextAtom()); + idx() = up; // the superscript has index 1 + pos() = size(); + ///lyxerr << "updown: handled by scriptinset to the left\n"; + return true; + } + } + + // try right + if (hasNextAtom()) { + MathScriptInset * p = nextAtom()->asScriptInset(); + if (p && p->has(up)) { + push(nextAtom()); + idx() = up; + pos() = 0; + ///lyxerr << "updown: handled by scriptinset to the right\n"; + return true; + } + } + + // try current cell + //xarray().boundingBox(xlow, xhigh, ylow, yhigh); + //if (up) + // yhigh = yo - 4; + //else + // ylow = yo + 4; + //if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) { + // lyxerr << "updown: handled by brute find in the same cell\n"; + // return true; + //} // try to find an inset that knows better then we while (1) { - // we found a cell that think something "below" us. - if (up) { - if (par()->idxUp(idx())) - break; - } else { - if (par()->idxDown(idx())) - break; + ///lyxerr << "updown: We are in " << *par() << " idx: " << idx() << '\n'; + // ask inset first + if (par()->idxUpDown(idx(), up)) { + // we found a cell that thinks it has something "below" us. + ///lyxerr << "updown: found inset that handles UpDown\n"; + xarray().boundingBox(xlow, xhigh, ylow, yhigh); + // project (xo,yo) onto proper box + ///lyxerr << "\n xo: " << xo << " yo: " << yo + /// << "\n xlow: " << xlow << " ylow: " << ylow + /// << "\n xhigh: " << xhigh << " yhigh: " << yhigh; + xo = min(max(xo, xlow), xhigh); + yo = min(max(yo, ylow), yhigh); + ///lyxerr << "\n xo2: " << xo << " yo2: " << yo << "\n"; + bruteFind(xo, yo, xlow, xhigh, ylow, yhigh); + ///lyxerr << "updown: handled by final brute find\n"; + return true; } + // leave inset if (!popLeft()) { // no such inset found, just take something "above" + ///lyxerr << "updown: handled by strange case\n"; return bruteFind(xo, yo, formula()->xlow(), @@ -1104,36 +1268,46 @@ bool MathCursor::goUpDown(bool up) up ? yo - 4 : formula()->yhigh() ); } + + // any improvement so far? + int xnew, ynew; + getPos(xnew, ynew); + if (up ? ynew < yo : ynew > yo) + return true; } - xarray().boundingBox(xlow, xhigh, ylow, yhigh); - bruteFind(xo, yo, xlow, xhigh, ylow, yhigh); - return true; } -bool MathCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh) +bool MathCursor::bruteFind + (int x, int y, int xlow, int xhigh, int ylow, int yhigh) { cursor_type best_cursor; double best_dist = 1e10; MathIterator it = ibegin(formula()->par().nucleus()); MathIterator et = iend(formula()->par().nucleus()); - for ( ; it != et; ++it) { - // avoid invalid nesting hen selecting - if (selection_ && !positionable(it.cursor(), Anchor_)) - continue; - int xo = it.position().xpos(); - int yo = it.position().ypos(); - if (xlow - 2 <= xo && xo <= xhigh + 2 && - ylow - 2 <= yo && yo <= yhigh + 2) - { - double d = (x - xo) * (x - xo) + (y - yo) * (y - yo); - if (d < best_dist) { - best_dist = d; - best_cursor = it.cursor(); + while (1) { + // avoid invalid nesting when selecting + if (!selection_ || positionable(it.cursor(), Anchor_)) { + MathCursorPos const & top = it.position(); + int xo = top.xpos(); + int yo = top.ypos(); + if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) { + double d = (x - xo) * (x - xo) + (y - yo) * (y - yo); + // '<=' in order to take the last possible position + // this is important for clicking behind \sum in e.g. '\sum_i a' + if (d <= best_dist) { + best_dist = d; + best_cursor = it.cursor(); + } } } + + if (it == et) + break; + ++it; } + if (best_dist < 1e10) Cursor_ = best_cursor; return best_dist < 1e10; @@ -1158,18 +1332,15 @@ bool MathCursor::interpret(string const & s) if (s.empty()) return true; - if (s.size() == 1) - return interpret(s[0]); - //lyxerr << "char: '" << s[0] << "' int: " << int(s[0]) << endl; - //owner_->getIntl()->getTrans().TranslateAndInsert(s[0], lt); + //owner_->getIntl()->getTrans().TranslateAndInsert(s[0], lt); //lyxerr << "trans: '" << s[0] << "' int: " << int(s[0]) << endl; if (s.size() >= 5 && s.substr(0, 5) == "cases") { unsigned int n = 1; istringstream is(s.substr(5).c_str()); is >> n; - n = std::max(1u, n); + n = max(1u, n); niceInsert(MathAtom(new MathCasesInset(n))); return true; } @@ -1181,10 +1352,10 @@ bool MathCursor::interpret(string const & s) string h_align; istringstream is(s.substr(6).c_str()); is >> m >> n >> v_align >> h_align; - m = std::max(1u, m); - n = std::max(1u, n); + m = max(1u, m); + n = max(1u, n); v_align += 'c'; - niceInsert(MathAtom(new MathArrayInset(m, n, v_align[0], h_align))); + niceInsert(MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align))); return true; } @@ -1200,9 +1371,11 @@ bool MathCursor::interpret(string const & s) return true; } - if (s == "\\over" || s == "\\choose" || s == "\\atop") { + string name = s.substr(1); + + if (name == "over" || name == "choose" || name == "atop") { MathArray ar = array(); - MathAtom t = createMathInset(s.substr(1)); + MathAtom t(createMathInset(name)); t->asNestInset()->cell(0).swap(array()); pos() = 0; niceInsert(t); @@ -1211,18 +1384,36 @@ bool MathCursor::interpret(string const & s) return true; } - latexkeys const * l = in_word_set(s.substr(1)); + latexkeys const * l = in_word_set(name); if (l && (l->token == LM_TK_FONT || l->token == LM_TK_OLDFONT)) { lastcode_ = static_cast(l->id); return true; } - niceInsert(createMathInset(s.substr(1))); + // prevent entering of recursive macros + if (formula()->lyxCode() == Inset::MATHMACRO_CODE + && formula()->getInsetName() == name) + { + lyxerr << "can't enter recursive macro\n"; + return true; + } + + niceInsert(createMathInset(name)); return true; } + bool MathCursor::script(bool up) { + // Hack to get \\^ and \\_ working + if (inMacroMode() && macroName() == "\\") { + if (up) + interpret("\\mathcircumflex"); + else + interpret('_'); + return true; + } + macroModeClose(); selCut(); if (hasPrevAtom() && prevAtom()->asScriptInset()) { @@ -1251,49 +1442,66 @@ bool MathCursor::script(bool up) bool MathCursor::interpret(char c) { //lyxerr << "interpret 2: '" << c << "'\n"; + if (inMacroArgMode()) { + --pos(); + plainErase(); + int n = c - '0'; + MathMacroTemplate * p = formula()->par()->asMacroTemplate(); + if (p && 1 <= n && n <= p->numargs()) + insert(MathAtom(new MathMacroArgument(c - '0', lastcode_))); + else { + insert(MathAtom(new MathSpecialCharInset('#'))); + interpret(c); // try again + } + return true; + } + // handle macroMode if (inMacroMode()) { string name = macroName(); + //lyxerr << "interpret name: '" << name << "'\n"; - if (name == "\\" && c == '#') { + // extend macro name if possible + if (isalpha(c)) { insert(c, LM_TC_TEX); return true; } - if (name == "\\" && c == '\\') { - backspace(); - interpret("\\backslash"); - return true; - } - - if (name == "\\#" && '1' <= c && c <= '9') { - insert(c, LM_TC_TEX); + // leave macro mode if explicitly requested + if (c == ' ') { macroModeClose(); return true; } - if (isalpha(c)) { - insert(c, LM_TC_TEX); - return true; - } - + // handle 'special char' macros if (name == "\\") { - insert(c, LM_TC_TEX); - macroModeClose(); + // remove the '\\' + backspace(); + if (c == '\\') + interpret("\\backslash"); + else + interpret(string("\\") + c); return true; } + // leave macro mode and try again macroModeClose(); + interpret(c); return true; } - if (selection_) + // just clear selection on pressing the space par + if (selection_ && c == ' ') { selClear(); + return true; + } - if (lastcode_ == LM_TC_TEXTRM) { - // suppress direct insertion of to spaces in a row + selClearOrDel(); + + if (lastcode_ == LM_TC_TEXTRM || par()->asBoxInset()) { + // suppress direct insertion of two spaces in a row // the still allows typing 'a' and deleting the 'a', but - // it is better than nothing + // it is better than nothing... if (c == ' ' && hasPrevAtom() && prevAtom()->getChar() == ' ') return true; insert(c, LM_TC_TEXTRM); @@ -1305,16 +1513,19 @@ bool MathCursor::interpret(char c) prevAtom()->asSpaceInset()->incSpace(); return true; } - - if (mathcursor->popRight()) + if (popRight()) return true; - // if are at the very end, leave the formula return pos() != size(); } + if (c == '#') { + insert(c, LM_TC_TEX); + return true; + } + /* - if (strchr("{}", c)) { + if (c == '{' || c == '}', c)) { insert(c, LM_TC_TEX); return true; } @@ -1329,8 +1540,8 @@ bool MathCursor::interpret(char c) return true; } - if (strchr("#$%", c)) { - insert(MathAtom(new MathSpecialCharInset(c))); + if (c == '$' || c == '%') { + insert(MathAtom(new MathSpecialCharInset(c))); lastcode_ = LM_TC_VAR; return true; } @@ -1349,11 +1560,11 @@ bool MathCursor::interpret(char c) if (c == '\\') { insert(c, LM_TC_TEX); //bv->owner()->message(_("TeX mode")); - return true; + return true; } // no special circumstances, so insert the character without any fuss - insert(c, lastcode_); + insert(c, lastcode_ == LM_TC_MIN ? MathCharInset::nativeCode(c) : lastcode_); lastcode_ = LM_TC_MIN; return true; } @@ -1389,7 +1600,23 @@ void MathCursor::stripFromLastEqualSign() // delete everything behind this position ar.erase(et - ar.begin(), ar.size()); - pos() = ar.size(); + pos() = ar.size(); +} + + +void MathCursor::setSelection(cursor_type const & where, size_type n) +{ + selection_ = true; + Anchor_ = where; + Cursor_ = where; + cursor().pos_ += n; } +string MathCursor::info() const +{ + ostringstream os; + if (pos() > 0) + prevAtom()->infoize(os); + return os.str().c_str(); // .c_str() needed for lyxstring +}