X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_cursor.C;h=36834e7612654ec9826a7aa0dd2ef95018f9a7f7;hb=06f9f0ea08ddcf13e99ea02cff21471aa2020c9e;hp=80796a9c6183951ca45d48dfda0c3b6031e4f303;hpb=546021819be846e583467fbae8c9cbd4cee02bb4;p=lyx.git diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 80796a9c61..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" @@ -48,6 +49,7 @@ #include "math_support.h" #include +#include #define FILEDEBUG 0 @@ -129,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))); } } @@ -238,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) @@ -255,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; @@ -305,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; } @@ -328,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; } @@ -357,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()) @@ -443,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))); } @@ -461,7 +456,7 @@ void MathCursor::insert(MathAtom const & t) if (t->nargs()) selCut(); else - selDel(); + selClearOrDel(); } plainInsert(t); @@ -536,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) { @@ -625,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); - } } @@ -661,7 +655,7 @@ void MathCursor::selCopy() dump("selCopy"); if (selection_) { theSelection.grab(*this); - selClear(); + //selClear(); } } @@ -694,9 +688,10 @@ void MathCursor::selDel() void MathCursor::selPaste() { dump("selPaste"); + selClearOrDel(); theSelection.paste(*this); //theSelection.grab(*this); - //selClear(); + selClear(); } @@ -728,6 +723,15 @@ void MathCursor::selClear() } +void MathCursor::selClearOrDel() +{ + if (lyxrc.auto_region_delete) + selDel(); + else + selClear(); +} + + void MathCursor::selGet(MathArray & ar) { dump("selGet"); @@ -823,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(); } @@ -888,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"); @@ -945,18 +960,18 @@ void MathCursor::normalize() } #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"); @@ -964,12 +979,14 @@ void MathCursor::normalize() pos() = min(pos(), size()); // remove empty scripts if possible - for (pos_type i = 0; i < size(); ++i) { - MathScriptInset * p = array().at(i)->asScriptInset(); - if (p) { - p->removeEmptyScripts(); - if (p->empty()) - array().erase(i); + 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); + } } } @@ -1174,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(), @@ -1209,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; @@ -1229,11 +1292,11 @@ bool MathCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhig MathCursorPos const & top = it.position(); int xo = top.xpos(); int yo = top.ypos(); - if (xlow - 2 <= xo && xo <= xhigh + 2 && - ylow - 2 <= yo && yo <= yhigh + 2) - { + 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(); } @@ -1269,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; @@ -1311,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); @@ -1322,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()) { @@ -1370,13 +1441,14 @@ 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'))); + insert(MathAtom(new MathMacroArgument(c - '0', lastcode_))); else { insert(MathAtom(new MathSpecialCharInset('#'))); interpret(c); // try again @@ -1387,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 if (c != ' ') - 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 @@ -1542,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 }