X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_cursor.C;h=36834e7612654ec9826a7aa0dd2ef95018f9a7f7;hb=06f9f0ea08ddcf13e99ea02cff21471aa2020c9e;hp=2698c5bed3fa8cd72e072c5a7d47c9c2fde09905;hpb=7ea7dabed1b72cc25dcbdc482ac006f2b61dacfd;p=lyx.git diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 2698c5bed3..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" @@ -38,6 +39,7 @@ #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" @@ -55,7 +57,6 @@ using std::endl; using std::min; using std::max; using std::swap; -using std::isalnum; using std::vector; using std::ostringstream; @@ -130,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))); } } @@ -202,14 +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(); - if (par()->asScriptInset()->empty()) - plainErase(); - } Cursor_.pop_back(); return true; } @@ -220,11 +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(); - if (par()->asScriptInset()->empty()) - plainErase(); - } Cursor_.pop_back(); posRight(); return true; @@ -249,12 +250,6 @@ 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) @@ -266,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; @@ -316,9 +308,6 @@ bool MathCursor::left(bool sel) lastcode_ = LM_TC_MIN; if (hasPrevAtom() && openable(prevAtom(), sel)) { - if (prevAtom()->isHyperActive()) { - lyxerr << "entering hyperactive inset\n"; - } pushRight(prevAtom()); return true; } @@ -339,12 +328,6 @@ bool MathCursor::right(bool sel) 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; } @@ -368,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()) @@ -454,6 +437,7 @@ void MathCursor::plainInsert(MathAtom const & t) void MathCursor::insert(char c, MathTextCodes t) { //lyxerr << "inserting '" << c << "'\n"; + selClearOrDel(); plainInsert(MathAtom(new MathCharInset(c, t))); } @@ -472,7 +456,7 @@ void MathCursor::insert(MathAtom const & t) if (t->nargs()) selCut(); else - selDel(); + selClearOrDel(); } plainInsert(t); @@ -547,18 +531,16 @@ 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) { @@ -636,13 +618,14 @@ 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); - } } @@ -672,7 +655,7 @@ void MathCursor::selCopy() dump("selCopy"); if (selection_) { theSelection.grab(*this); - selClear(); + //selClear(); } } @@ -705,9 +688,10 @@ void MathCursor::selDel() void MathCursor::selPaste() { dump("selPaste"); + selClearOrDel(); theSelection.paste(*this); //theSelection.grab(*this); - //selClear(); + selClear(); } @@ -739,6 +723,15 @@ void MathCursor::selClear() } +void MathCursor::selClearOrDel() +{ + if (lyxrc.auto_region_delete) + selDel(); + else + selClear(); +} + + void MathCursor::selGet(MathArray & ar) { dump("selGet"); @@ -834,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(); } @@ -899,12 +895,20 @@ MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const 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"); @@ -934,8 +938,18 @@ void MathCursor::pullArg(bool goright) } +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()); @@ -944,24 +958,40 @@ void MathCursor::normalize() 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()); } @@ -1161,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(), @@ -1196,14 +1268,18 @@ 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; @@ -1213,13 +1289,14 @@ bool MathCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhig while (1) { // avoid invalid nesting when selecting if (!selection_ || positionable(it.cursor(), Anchor_)) { - int xo = it.position().xpos(); - int yo = it.position().ypos(); - if (xlow - 2 <= xo && xo <= xhigh + 2 && - ylow - 2 <= yo && yo <= yhigh + 2) - { + 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); - if (d < best_dist) { + // '<=' 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(); } @@ -1255,9 +1332,6 @@ 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); //lyxerr << "trans: '" << s[0] << "' int: " << int(s[0]) << endl; @@ -1297,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); @@ -1308,27 +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; } // prevent entering of recursive macros - if (formula()->lyxCode() == Inset::MATHMACRO_CODE - && formula()->getInsetName() == s.substr(1)) + if (formula()->lyxCode() == Inset::MATHMACRO_CODE + && formula()->getInsetName() == name) { lyxerr << "can't enter recursive macro\n"; return true; } - niceInsert(createMathInset(s.substr(1))); + 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()) { @@ -1356,11 +1441,14 @@ bool MathCursor::script(bool up) bool MathCursor::interpret(char c) { + //lyxerr << "interpret 2: '" << c << "'\n"; if (inMacroArgMode()) { --pos(); plainErase(); - if ('1' <= c && c <= '9') - insert(MathAtom(new MathMacroArgument(c - '0'))); + 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 @@ -1371,41 +1459,45 @@ bool MathCursor::interpret(char c) // handle macroMode if (inMacroMode()) { string name = macroName(); + //lyxerr << "interpret name: '" << name << "'\n"; - if (name == "\\" && c == '\\') { - backspace(); - interpret("\\backslash"); + // extend macro name if possible + if (isalpha(c)) { + insert(c, LM_TC_TEX); return true; } - if (isalpha(c)) { - insert(c, LM_TC_TEX); + // leave macro mode if explicitly requested + if (c == ' ') { + macroModeClose(); 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(); - - if (c == '\\') - insert(c, LM_TC_TEX); - else - insert(c, lastcode_); - + 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 @@ -1433,7 +1525,7 @@ bool MathCursor::interpret(char c) } /* - if (strchr("{}", c)) { + if (c == '{' || c == '}', c)) { insert(c, LM_TC_TEX); return true; } @@ -1448,7 +1540,7 @@ bool MathCursor::interpret(char c) return true; } - if (strchr("$%", c)) { + if (c == '$' || c == '%') { insert(MathAtom(new MathSpecialCharInset(c))); lastcode_ = LM_TC_VAR; return true; @@ -1526,5 +1618,5 @@ string MathCursor::info() const ostringstream os; if (pos() > 0) prevAtom()->infoize(os); - return os.str(); + return os.str().c_str(); // .c_str() needed for lyxstring }