X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_cursor.C;h=36834e7612654ec9826a7aa0dd2ef95018f9a7f7;hb=06f9f0ea08ddcf13e99ea02cff21471aa2020c9e;hp=2cc8113baf1c77baf7e2a85cb2991c54cf04948d;hpb=f4892a2d334b8421999b03f70b962a0aaeab018d;p=lyx.git diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 2cc8113baf..36834e7612 100644 --- a/src/mathed/math_cursor.C +++ b/src/mathed/math_cursor.C @@ -16,6 +16,7 @@ */ #include +#include #ifdef __GNUG__ #pragma implementation @@ -25,7 +26,7 @@ #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" @@ -37,6 +38,8 @@ #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" @@ -54,7 +57,8 @@ using std::endl; using std::min; using std::max; using std::swap; -using std::isalnum; +using std::vector; +using std::ostringstream; namespace { @@ -75,18 +79,18 @@ struct Selection c1 = p->col(i1.idx_); c2 = p->col(i2.idx_); if (c1 > c2) - std::swap(c1, c2); + swap(c1, c2); r1 = p->row(i1.idx_); r2 = p->row(i2.idx_); if (r1 > r2) - std::swap(r1, r2); + swap(r1, r2); } void grab(MathCursor const & cursor) { MathCursorPos i1; MathCursorPos i2; - cursor.getSelection(i1, i2); + cursor.getSelection(i1, i2); // shouldn'tt we assert on i1.par_ == i2.par_? if (i1.idx_ == i2.idx_) { data_ = MathGridInset(1, 1); @@ -94,9 +98,9 @@ struct Selection } else { row_type r1, r2; col_type c1, c2; - region(i1, i2, r1, r2, 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 (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); @@ -108,15 +112,15 @@ 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 { 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) + 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(); } @@ -127,18 +131,28 @@ struct Selection { if (data_.nargs() == 1) { // single cell/part of cell - cursor.insert(data_.cell(0)); + cursor.paste(data_.cell(0)); } else { // mulitple cells - idx_type idx; + 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 (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))); } } @@ -168,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(); } @@ -199,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; } @@ -214,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; @@ -240,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; } @@ -257,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; @@ -300,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_; } @@ -323,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; } @@ -359,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()) @@ -396,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"); } @@ -408,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"); @@ -421,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); @@ -431,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(); @@ -443,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! @@ -488,7 +501,7 @@ void MathCursor::backspace() if (pos() == 0) { pullArg(false); return; - } + } if (selection_) { selDel(); @@ -498,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; } @@ -518,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; } @@ -558,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(); @@ -607,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; @@ -631,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; } @@ -642,7 +655,7 @@ void MathCursor::selCopy() dump("selCopy"); if (selection_) { theSelection.grab(*this); - selClear(); + //selClear(); } } @@ -675,9 +688,10 @@ void MathCursor::selDel() void MathCursor::selPaste() { dump("selPaste"); + selClearOrDel(); theSelection.paste(*this); //theSelection.grab(*this); - //selClear(); + selClear(); } @@ -709,6 +723,15 @@ void MathCursor::selClear() } +void MathCursor::selClearOrDel() +{ + if (lyxrc.auto_region_delete) + selDel(); + else + selClear(); +} + + void MathCursor::selGet(MathArray & ar) { dump("selGet"); @@ -738,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]); @@ -770,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; } @@ -804,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(); } @@ -850,6 +876,12 @@ bool MathCursor::inMacroMode() const } +bool MathCursor::inMacroArgMode() const +{ + return pos() > 0 && prevAtom()->getChar() == '#'; +} + + bool MathCursor::selection() const { return selection_; @@ -858,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"); @@ -890,40 +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::touch() +{ + 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) + for (; it != et; ++it) if (it.par()->asBoxInset()) it.par()->asBoxInset()->rebreak(); } +#endif - if (idx() >= par()->nargs()) { + if (idx() >= par()->nargs()) { lyxerr << "this should not really happen - 1: " << idx() << " " << par()->nargs() << "\n"; dump("error 2"); } - 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: " << idx() << " in atom: '"; - WriteStream wi(lyxerr, false); + WriteStream wi(lyxerr, false, true); par()->write(wi); lyxerr << "\n"; dump("error 4"); } 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()); } @@ -1030,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()); @@ -1123,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(), @@ -1158,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; @@ -1212,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; } @@ -1235,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; } @@ -1254,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); @@ -1265,19 +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()) { @@ -1306,49 +1442,62 @@ 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(); - if (c == ' ') - return true; - // fall through in the other cases + return true; } + 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 @@ -1370,8 +1519,13 @@ bool MathCursor::interpret(char c) 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; } @@ -1386,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; } @@ -1406,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; } @@ -1446,7 +1600,7 @@ void MathCursor::stripFromLastEqualSign() // delete everything behind this position ar.erase(et - ar.begin(), ar.size()); - pos() = ar.size(); + pos() = ar.size(); } @@ -1457,3 +1611,12 @@ void MathCursor::setSelection(cursor_type const & where, size_type n) 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 +}