X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_cursor.C;h=c12b10223e2f66daf339418349505741d50efce9;hb=3024e24e80a40ca97ef66310610515ec2c3b6457;hp=51eeedf525eac21c0568fe42ea8135355639bfc5;hpb=4a40b711f2fe6ce8638a15f5bc7644a581cab016;p=lyx.git diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 51eeedf525..c12b10223e 100644 --- a/src/mathed/math_cursor.C +++ b/src/mathed/math_cursor.C @@ -20,45 +20,131 @@ #endif #include +#include #include -#include "math_inset.h" -#include "math_arrayinset.h" -#include "math_parser.h" -#include "math_cursor.h" -#include "math_macro.h" -#include "math_macroarg.h" -#include "math_macrotable.h" -#include "math_root.h" -#include "support/lstrings.h" #include "debug.h" #include "LColor.h" #include "Painter.h" -#include "math_matrixinset.h" -#include "math_grid.h" -#include "math_spaceinset.h" -#include "math_funcinset.h" +#include "mathed/support.h" +#include "formulabase.h" +#include "math_cursor.h" +#include "math_arrayinset.h" #include "math_bigopinset.h" -#include "math_fracinset.h" #include "math_decorationinset.h" -#include "math_dotsinset.h" #include "math_deliminset.h" +#include "math_dotsinset.h" +#include "math_fracinset.h" +#include "math_funcinset.h" +#include "math_gridinset.h" +#include "math_macro.h" +#include "math_macroarg.h" +#include "math_macrotable.h" #include "math_macrotemplate.h" +#include "math_matrixinset.h" +#include "math_rootinset.h" +#include "math_spaceinset.h" #include "math_sqrtinset.h" +#include "support/lstrings.h" #include "math_scriptinset.h" -#include "mathed/support.h" -#include "formulabase.h" - +#include "math_parser.h" using std::endl; using std::min; using std::max; using std::isalnum; +#define RECTANGULAR_SELECT 1 namespace { -MathArray selarray; +struct Selection +{ + 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 { +#ifdef RECTANGULAR_SELECT + std::vector indices = i1.par_->idxBetween(i1.idx_, i2.idx_); + for (unsigned i = 0; i < indices.size(); ++i) + data_.push_back(i1.cell(indices[i])); +#else + data_.push_back(MathArray(i1.cell(), i1.pos_, i1.cell().size())); + for (int i = i1.idx_ + 1; i < i2.idx_; ++i) + data_.push_back(i1.cell(i)); + data_.push_back(MathArray(i2.cell(), 0, i2.pos_)); +#endif + } + } + + void erase(MathCursor & cursor) + { + MathCursorPos i1; + MathCursorPos i2; + cursor.getSelection(i1, i2); + if (i1.idx_ == i2.idx_) { + i1.cell().erase(i1.pos_, i2.pos_); + } else { +#ifdef RECTANGULAR_SELECT + std::vector indices = i1.par_->idxBetween(i1.idx_, i2.idx_); + for (unsigned i = 0; i < indices.size(); ++i) + i1.cell(indices[i]).erase(); +#else + i1.cell().erase(i1.pos_, i1.cell().size()); + for (int i = i1.idx_ + 1; i < i2.idx_; ++i) + i1.cell(i).erase(); + i2.cell().erase(0, i2.pos_); + + int from = i1.cell().size() ? i1.idx_ + 1 : i1.idx_; + int to = i2.cell().size() ? i2.idx_ : i2.idx_ + 1; + i1.par_->idxDeleteRange(from, to); +#endif + } + cursor.cursor() = i1; + } + + void paste(MathCursor & cursor) const + { +#ifdef RECTANGULAR_SELECT + cursor.cursor().cell().push_back(glue()); +#else + unsigned na = cursor.cursor().par_->nargs(); + unsigned idx = cursor.cursor().idx_; + unsigned end = std::min(idx + data_.size(), na); + for (int i = 0; i < end - idx; ++i) + cursor.cursor().cell(idx + i).push_back(data_[i]); + for (unsigned i = end - idx; i < data_.size(); ++i) + cursor.cursor().cell(end - 1).push_back(data_[i]); +#endif + } + + // glues selection to one cell + MathArray glue() const + { + MathArray ar; + for (unsigned i = 0; i < data_.size(); ++i) + ar.push_back(data_[i]); + return ar; + } + + void clear() + { + data_.clear(); + } + + + + std::vector data_; +}; + + +Selection theSelection; + bool IsMacro(short tok, int id) { @@ -73,83 +159,115 @@ bool IsMacro(short tok, int id) !(tok == LM_TK_SYM && id < 255); } + +std::ostream & operator<<(std::ostream & os, MathCursorPos const & p) +{ + os << "(par: " << p.par_ << " idx: " << p.idx_ + << " pos: " << p.pos_ << ")"; + return os; +} + } + MathCursor::MathCursor(InsetFormulaBase * formula) : formula_(formula) { lastcode = LM_TC_MIN; macro_mode = false; + selection = false; first(); } void MathCursor::push(MathInset * par, bool first) { - path_.push_back(MathIter()); - path_.back().par_ = par_; - path_.back().idx_ = idx_; - path_.back().cursor_ = cursor_; - dump("Pushed:"); - par_ = par; - first ? par_->idxFirst(idx_, cursor_) : par_->idxLast(idx_, cursor_); + MathCursorPos p; + p.par_ = par; + if (first) + par->idxFirst(p.idx_, p.pos_); + else + par->idxLast(p.idx_, p.pos_); + Cursor_.push_back(p); } bool MathCursor::pop() { - if (path_.empty()) + if (Cursor_.size() <= 1) return false; - par_ = path_.back().par_; - idx_ = path_.back().idx_; - cursor_ = path_.back().cursor_; - dump("Popped:"); - path_.pop_back(); + Cursor_.pop_back(); return true; } MathInset * MathCursor::parInset(int i) const { - return path_[i].par_; + return Cursor_[i].par_; } + void MathCursor::dump(char const * what) const { return; - lyxerr << "MC: " << what - << " cursor: " << cursor_ - << " anchor: " << anchor_ - << " idx: " << idx_ - << " par: " << par_ - << " sel: " << selection - << " data: " << array() - << "\n"; + lyxerr << "MC: " << what << "\n"; + for (unsigned i = 0; i < Cursor_.size(); ++i) + lyxerr << " i: " << i + << " pos: " << Cursor_[i].pos_ + << " idx: " << Cursor_[i].idx_ + << " par: " << Cursor_[i].par_ << "\n"; + + //lyxerr << " sel: " << selection << " data: " << array() << "\n"; } -void MathCursor::seldump(char const * str) const + +void MathCursor::seldump(char const *) const { - lyxerr << "SEL: " << str << ": '" << selarray << "'\n"; - dump(" Pos"); + //lyxerr << "SEL: " << str << ": '" << theSelection << "'\n"; + //dump(" Pos"); return; - lyxerr << "\n\n\\n=================vvvvvvvvvvvvv======================= " - << str << "\nselarray: " << selarray; - for (unsigned int i = 0; i < path_.size(); ++i) - lyxerr << path_[i].par_ << "\n'" << path_[i].par_->cell(0) << "'\n"; - lyxerr << "\ncursor: " << cursor_; - lyxerr << "\nanchor: " << anchor_; - lyxerr << "\n===================^^^^^^^^^^^^=====================\n\n\n"; + //lyxerr << "\n\n\\n=================vvvvvvvvvvvvv======================= " + // << str << "\ntheSelection: " << theSelection; + //for (unsigned int i = 0; i < Cursor_.size(); ++i) + // lyxerr << Cursor_[i].par_ << "\n'" << Cursor_[i].cell() << "'\n"; + //lyxerr << "\ncursor.pos_: " << cursor().pos_; + //lyxerr << "\nanchor.pos_: " << anchor().pos_; + //lyxerr << "\n===================^^^^^^^^^^^^=====================\n\n\n"; } bool MathCursor::isInside(MathInset * p) const { - for (unsigned i = 0; i < path_.size(); ++i) + for (unsigned i = 0; i < Cursor_.size(); ++i) if (parInset(i) == p) return true; - return par_ == p; + return false; +} + + +bool MathCursor::openable(MathInset * p, bool sel, bool useupdown) const +{ + if (!p) + return false; + if (!(p->isActive() || (useupdown && p->isUpDownInset()))) + return false; + + if (sel) { + // we can't move into everything during selection + if (Cursor_.size() == Anchor_.size()) + return false; + if (p != Anchor_[Cursor_.size()].par_) + return false; + } + return true; +} + + +bool MathCursor::plainLeft() +{ + return array().prev(cursor().pos_); } @@ -165,45 +283,28 @@ bool MathCursor::Left(bool sel) MacroModeClose(); return true; } - clearLastCode(); SelHandle(sel); + clearLastCode(); - bool result = false; - - if (selection) { - result = array().prev(cursor_); - if (!result && pop()) { - anchor_ = cursor_; - result = array().next(anchor_); - } - } else { - MathInset * p = prevInset(); - if (p && p->isActive()) { - // We have to move deeper into the previous inset - array().prev(cursor_); - push(p, false); - result = true; - } else { - // The common case, where we are not - // entering a deeper inset - result = array().prev(cursor_); - if (!result) { - if (par_->idxLeft(idx_, cursor_)) { - result = true; - } else if (pop()) { - result = true; - } - } - } - } - dump("Left 2"); - return result; + MathInset * p = prevInset(); + if (openable(p, sel, false)) { + plainLeft(); + push(p, false); + return true; + } + if (plainLeft()) + return true; + if (cursor().par_->idxLeft(cursor().idx_, cursor().pos_)) + return true; + if (pop()) + return true; + return false; } bool MathCursor::plainRight() { - return array().next(cursor_); + return array().next(cursor().pos_); } @@ -214,59 +315,36 @@ bool MathCursor::Right(bool sel) MacroModeClose(); return true; } - - clearLastCode(); SelHandle(sel); + clearLastCode(); - bool result = false; - - if (selection) { - result = array().next(cursor_); - if (!result && pop()) { - anchor_ = cursor_; - result = array().next(cursor_); - } - } else { - MathInset * p = nextInset(); - if (p && p->isActive()) { - push(p, true); - result = true; - } else { - result = array().next(cursor_); - if (!result) { - if (par_->idxRight(idx_, cursor_)) { - result = true; - } else if (pop()) { - result = true; - array().next(cursor_); - } - } - } + MathInset * p = nextInset(); + if (openable(p, sel, false)) { + push(p, true); + return true; } - dump("Right 2"); - return result; + if (array().next(cursor().pos_)) + return true; + if (cursor().par_->idxRight(cursor().idx_, cursor().pos_)) + return true; + if (!pop()) + return false; + array().next(cursor().pos_); + return true; } void MathCursor::first() { - selection = false; - par_ = formula_->par(); - idx_ = 0; - cursor_ = 0; - anchor_ = 0; - par_->idxFirst(idx_, cursor_); + Cursor_.clear(); + push(formula_->par(), true); } void MathCursor::last() { - selection = false; - par_ = formula_->par(); - idx_ = 0; - cursor_ = 0; - anchor_ = 0; - par_->idxLast(idx_, cursor_); + Cursor_.clear(); + push(formula_->par(), false); } @@ -277,17 +355,17 @@ void MathCursor::SetPos(int x, int y) MacroModeClose(); lastcode = LM_TC_MIN; - path_.clear(); + first(); - par_ = formula()->par(); + cursor().par_ = formula()->par(); while (1) { - idx_ = -1; - cursor_ = -1; - //lyxerr << "found idx: " << idx_ << " cursor: " << cursor_ << "\n"; + cursor().idx_ = -1; + cursor().pos_ = -1; + //lyxerr << "found idx: " << idx_ << " cursor: " << cursor().pos_ << "\n"; int distmin = 1 << 30; // large enough - for (int i = 0; i < par_->nargs(); ++i) { - MathXArray const & ar = par_->xcell(i); + for (int i = 0; i < cursor().par_->nargs(); ++i) { + MathXArray const & ar = cursor().par_->xcell(i); int x1 = x - ar.xo(); int y1 = y - ar.yo(); int c = ar.x2pos(x1); @@ -296,18 +374,19 @@ void MathCursor::SetPos(int x, int y) //lyxerr << "idx: " << i << " xx: " << xx << " yy: " << yy // << " c: " << c << " xo: " << ar.xo() << "\n"; if (yy + xx <= distmin) { - distmin = yy + xx; - idx_ = i; - cursor_ = c; + distmin = yy + xx; + cursor().idx_ = i; + cursor().pos_ = c; } } - lyxerr << "found idx: " << idx_ << " cursor: " << cursor_ << "\n"; + //lyxerr << "found idx: " << cursor().idx_ << " cursor: " + // << cursor().pos_ << "\n"; MathInset * n = nextInset(); MathInset * p = prevInset(); - if (n && (n->isActive() || n->isUpDownInset()) && n->covers(x, y)) + if (openable(n, selection, true) && n->covers(x, y)) push(n, true); - else if (p && (p->isActive() || p->isUpDownInset()) && p->covers(x, y)) { - array().prev(cursor_); + else if (openable(p, selection, true) && p->covers(x, y)) { + plainLeft(); push(p, false); } else break; @@ -322,9 +401,8 @@ void MathCursor::Home() if (macro_mode) MacroModeClose(); clearLastCode(); - if (!par_->idxHome(idx_, cursor_)) { + if (!cursor().par_->idxHome(cursor().idx_, cursor().pos_)) pop(); - } dump("Home 2"); } @@ -335,9 +413,9 @@ void MathCursor::End() if (macro_mode) MacroModeClose(); clearLastCode(); - if (!par_->idxEnd(idx_, cursor_)) { + if (!cursor().par_->idxEnd(cursor().idx_, cursor().pos_)) { pop(); - array().next(cursor_); + array().next(cursor().pos_); } dump("End 2"); } @@ -363,8 +441,8 @@ void MathCursor::insert(char c, MathTextCodes t) } } - array().insert(cursor_, c, t); - array().next(cursor_); + array().insert(cursor().pos_, c, t); + array().next(cursor().pos_); lastcode = t; } @@ -381,8 +459,19 @@ void MathCursor::insert(MathInset * p) SelDel(); } - array().insert(cursor_, p); - array().next(cursor_); + array().insert(cursor().pos_, p); + array().next(cursor().pos_); +} + + +void MathCursor::insert(MathArray const & ar) +{ + MacroModeClose(); + if (selection) + SelCut(); + + array().insert(cursor().pos_, ar); + cursor().pos_ += ar.size(); } @@ -397,26 +486,18 @@ void MathCursor::Delete() return; } - if (cursor_ < array().size()) - array().erase(cursor_); + if (cursor().pos_ < array().size()) + array().erase(cursor().pos_); // delete empty cells if necessary - if (cursor_ == 0 && array().size() == 0) { + if (cursor().pos_ == 0 && array().size() == 0) { bool popit; bool removeit; - par_->idxDelete(idx_, popit, removeit); + cursor().par_->idxDelete(cursor().idx_, popit, removeit); if (popit && pop() && removeit) Delete(); } -#ifdef WITH_WARNINGS -#warning pullArg disabled -#endif - //if (cursor_ == 0 && !path_.empty()) { - // lyxerr << "Delete: popping...\n"; - // pop(); - //} - dump("Delete 2"); } @@ -430,8 +511,8 @@ void MathCursor::DelLine() return; } - if (par_->nrows() > 1) - par_->delRow(row()); + if (cursor().par_->nrows() > 1) + cursor().par_->delRow(row()); } @@ -440,17 +521,27 @@ bool MathCursor::Up(bool sel) dump("Up 1"); MacroModeClose(); SelHandle(sel); - SelClear(); + + if (selection) { + int x = xarray().pos2x(cursor().pos_); + if (cursor().par_->idxUp(cursor().idx_, cursor().pos_)) { + cursor().pos_ = xarray().x2pos(x); + return true; + } + if (pop()) + return true; + return false; + } // check whether we could move into an inset on the right or on the left MathInset * p = nextInset(); if (p) { - int idx, cursor; - if (p->idxFirstUp(idx, cursor)) { + int idx, pos; + if (p->idxFirstUp(idx, pos)) { push(p, true); - par_ = p; - idx_ = idx; - cursor_ = cursor; + cursor().par_ = p; + cursor().idx_ = idx; + cursor().pos_ = pos; dump("Up 3"); return true; } @@ -458,28 +549,26 @@ bool MathCursor::Up(bool sel) p = prevInset(); if (p) { - int idx, cursor; - if (p->idxLastUp(idx, cursor)) { - array().prev(cursor_); + int idx, pos; + if (p->idxLastUp(idx, pos)) { + plainLeft(); push(p, false); - par_ = p; - idx_ = idx; - cursor_ = cursor; + cursor().par_ = p; + cursor().idx_ = idx; + cursor().pos_ = pos; dump("Up 4"); return true; } } - - int x = xarray().pos2x(cursor_); - bool result = par_->idxUp(idx_, cursor_); - if (!result && pop()) { - result = par_->idxUp(idx_, cursor_); + int x = xarray().pos2x(cursor().pos_); + if (cursor().idxUp()) { + cursor().pos_ = xarray().x2pos(x); + return true; } - cursor_ = xarray().x2pos(x); - - dump("Up 2"); - return result; + if (pop()) + return true; + return false; } @@ -488,16 +577,26 @@ bool MathCursor::Down(bool sel) dump("Down 1"); MacroModeClose(); SelHandle(sel); - SelClear(); + + if (selection) { + int x = xarray().pos2x(cursor().pos_); + if (cursor().idxDown()) { + cursor().pos_ = xarray().x2pos(x); + return true; + } + if (pop()) + return true; + return false; + } // check whether we could move into an inset on the right or on the left MathInset * p = nextInset(); if (p) { - int idx, cursor; - if (p->idxFirstDown(idx, cursor)) { + int idx, pos; + if (p->idxFirstDown(idx, pos)) { push(p, true); - idx_ = idx; - cursor_ = cursor; + cursor().idx_ = idx; + cursor().pos_ = pos; dump("Down 3"); return true; } @@ -505,26 +604,25 @@ bool MathCursor::Down(bool sel) p = prevInset(); if (p) { - int idx, cursor; - if (p->idxLastDown(idx, cursor)) { - array().prev(cursor_); + int idx, pos; + if (p->idxLastDown(idx, pos)) { + plainLeft(); push(p, false); - idx_ = idx; - cursor_ = cursor; + cursor().idx_ = idx; + cursor().pos_ = pos; dump("Down 4"); return true; } } - int x = xarray().pos2x(cursor_); - bool result = par_->idxDown(idx_, cursor_); - if (!result && pop()) { - result = par_->idxDown(idx_, cursor_); + int x = xarray().pos2x(cursor().pos_); + if (cursor().par_->idxDown(cursor().idx_, cursor().pos_)) { + cursor().pos_ = xarray().x2pos(x); + return true; } - cursor_ = xarray().x2pos(x); - - dump("Down 2"); - return result; + if (pop()) + return true; + return false; } @@ -541,7 +639,7 @@ bool MathCursor::toggleLimits() void MathCursor::SetSize(MathStyles size) { - par_->UserSetSize(size); + cursor().par_->UserSetSize(size); } @@ -556,11 +654,11 @@ in_word_set(s) << " \n"; if (!p) { p = new MathScriptInset(true, false); insert(p); - array().prev(cursor_); + plainLeft(); } push(p, true); p->up(true); - idx_ = 0; + cursor().idx_ = 0; return; } @@ -569,11 +667,11 @@ in_word_set(s) << " \n"; if (!p) { p = new MathScriptInset(false, true); insert(p); - array().prev(cursor_); + plainLeft(); } push(p, true); p->down(true); - idx_ = 1; + cursor().idx_ = 1; return; } @@ -596,10 +694,11 @@ in_word_set(s) << " \n"; int n = 1; string v_align; string h_align; - std::istringstream is(s.substr(7).c_str()); + istringstream is(s.substr(7).c_str()); is >> m >> n >> v_align >> h_align; m = std::max(1, m); n = std::max(1, n); + v_align += 'c'; MathArrayInset * pp = new MathArrayInset(m, n); pp->valign(v_align[0]); pp->halign(h_align); @@ -613,16 +712,14 @@ in_word_set(s) << " \n"; p = new MathBigopInset(l->name, l->id); break; - case LM_TK_SYM: - if (l->id < 255) { - insert(static_cast(l->id), - MathIsBOPS(l->id) ? - LM_TC_BOPS : LM_TC_SYMB); - - } else { + case LM_TK_SYM: { + MathTextCodes code = static_cast(l->id); + if (code < 255) + insert(l->id, MathIsBOPS(code) ? LM_TC_BOPS : LM_TC_SYMB); + else p = new MathFuncInset(l->name); - } break; + } case LM_TK_STACK: p = new MathFracInset("stackrel"); @@ -668,7 +765,7 @@ in_word_set(s) << " \n"; SelCut(); insert(p); if (p->nargs()) { - array().prev(cursor_); + plainLeft(); push(p, true); if (oldsel) SelPaste(); @@ -706,7 +803,7 @@ void MathCursor::MacroModeClose() imacro->SetName(l->name); } else { Left(); - array().erase(cursor_); + array().erase(cursor().pos_); if (l || MathMacroTable::hasTemplate(imacro->name())) Interpret(imacro->name()); imacro->SetName(string()); @@ -720,26 +817,18 @@ void MathCursor::SelCopy() { seldump("SelCopy"); if (selection) { - int const p1 = min(cursor_, anchor_); - int const p2 = max(cursor_, anchor_); - selarray = array(); - selarray.erase(p2, selarray.size()); - selarray.erase(0, p1); + theSelection.grab(*this); SelClear(); } } + void MathCursor::SelCut() { seldump("SelCut"); if (selection) { - int const p1 = min(cursor_, anchor_); - int const p2 = max(cursor_, anchor_); - cursor_ = p1; // move cursor to a same position - selarray = array(); - selarray.erase(p2, selarray.size()); - selarray.erase(0, p1); - array().erase(p1, p2); + theSelection.grab(*this); + theSelection.erase(*this); SelClear(); } } @@ -749,9 +838,7 @@ void MathCursor::SelDel() { seldump("SelDel"); if (selection) { - int const p1 = min(cursor_, anchor_); - int const p2 = max(cursor_, anchor_); - array().erase(p1, p2); + theSelection.erase(*this); SelClear(); } } @@ -760,11 +847,11 @@ void MathCursor::SelDel() void MathCursor::SelPaste() { seldump("SelPaste"); - array().insert(cursor_, selarray); - cursor_ += selarray.size(); + theSelection.paste(*this); SelClear(); } + void MathCursor::SelHandle(bool sel) { if (sel && !selection) @@ -780,7 +867,7 @@ void MathCursor::SelStart() if (selection) return; - anchor_ = cursor_; + Anchor_ = Cursor_; selection = true; } @@ -791,89 +878,81 @@ void MathCursor::SelClear() } - -void MathCursor::SelGetArea(int * xpoint, int * ypoint, int & n) +void MathCursor::drawSelection(Painter & pain) const { - if (!selection) { - n = 0; - xpoint[0] = 0; - ypoint[0] = 0; + if (!selection) return; - } - // Balance anchor and cursor - int xo; - int yo; - par()->GetXY(xo, yo); - int w = par()->width(); - // cursor - int x1 = xarray().xo() + xarray().pos2x(cursor_); - int y1 = xarray().yo(); - //int a1 = xarray().ascent(); - //int d1 = xarray().descent(); - - // anchor - int x = xarray().xo() + xarray().pos2x(anchor_); - int y = xarray().yo(); - int a = xarray().ascent(); - int d = xarray().descent(); - - // single row selection - n = 0; - xpoint[n] = x; - ypoint[n++] = y + d; - xpoint[n] = x; - ypoint[n++] = y - a; - - if (y != y1) { - xpoint[n] = xo + w; - ypoint[n++] = y - a; - - if (x1 < xo + w) { - xpoint[n] = xo + w; - ypoint[n++] = y1 - a; - } - } + MathCursorPos i1; + MathCursorPos i2; + getSelection(i1, i2); + + //lyxerr << "selection from: " << i1 << " to " << i2 << "\n"; + + if (i1.idx_ == i2.idx_) { + MathXArray & c = i1.xcell(); + int x1 = c.xo() + c.pos2x(i1.pos_); + int y1 = c.yo() - c.ascent(); + int x2 = c.xo() + c.pos2x(i2.pos_); + int y2 = c.yo() + c.descent(); + pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); + } else { - xpoint[n] = x1; - ypoint[n++] = y1 - a; - xpoint[n] = x1; - ypoint[n++] = y1 + d; - - if (y != y1) { - xpoint[n] = xo; - ypoint[n++] = y1 + d; - if (x > xo) { - xpoint[n] = xo; - ypoint[n++] = y + d; +#if RECTANGULAR_SELECT + std::vector indices = i1.par_->idxBetween(i1.idx_, i2.idx_); + for (unsigned i = 0; i < indices.size(); ++i) { + MathXArray & c = i1.xcell(indices[i]); + int x1 = c.xo(); + int y1 = c.yo() - c.ascent(); + int x2 = c.xo() + c.width(); + int y2 = c.yo() + c.descent(); + pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); + } +#else + // leftmost cell + MathXArray & c = i1.xcell(); + int x1 = c.xo() + c.pos2x(i1.pos_); + int y1 = c.yo() - c.ascent(); + int x2 = c.xo() + c.width(); + int y2 = c.yo() + c.descent(); + pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); + // middle cells + for (int idx = i1.idx_ + 1; idx < i2.idx_; ++idx) { + MathXArray & c = i1.xcell(idx); + int x1 = c.xo(); + int y1 = c.yo() - c.ascent(); + int x2 = c.xo() + c.width(); + int y2 = c.yo() + c.descent(); + pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); } + // rightmost cell + MathXArray & cr = i2.xcell(); + x1 = cr.xo(); + y1 = cr.yo() - cr.ascent(); + x2 = cr.xo() + cr.pos2x(i2.pos_); + y2 = cr.yo() + cr.descent(); + pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection); +#endif } - xpoint[n] = xpoint[0]; - ypoint[n++] = ypoint[0]; - - //lyxerr << "AN[" << x << " " << y << " " << x1 << " " << y1 << "]\n"; - //lyxerr << "MT[" << a << " " << d << " " << a1 << " " << d1 << "]\n"; - //for (i = 0; i < np; ++i) - // lyxerr << "XY[" << xpoint[i] << " " << ypoint[i] << "]\n"; } void MathCursor::handleFont(MathTextCodes t) { - if (selection) { - int const p1 = std::min(cursor_, anchor_); - int const p2 = std::max(cursor_, anchor_); - MathArray & ar = array(); - for (int pos = p1; pos != p2; ar.next(pos)) - if (!ar.isInset(pos) && isalnum(ar.GetChar(pos))) { - MathTextCodes c = ar.GetCode(pos) == t ? LM_TC_VAR : t; - ar.setCode(pos, c); - } + if (selection) { + MathCursorPos i1; + MathCursorPos i2; + getSelection(i1, i2); + if (i1.idx_ == i2.idx_) { + MathArray & ar = i1.cell(); + for (int pos = i1.pos_; pos != i2.pos_; ar.next(pos)) + if (!ar.isInset(pos) && isalnum(ar.GetChar(pos))) { + MathTextCodes c = ar.GetCode(pos) == t ? LM_TC_VAR : t; + ar.setCode(pos, c); + } + } } else { - if (lastcode == t) - lastcode = LM_TC_VAR; - else - lastcode = t; + lastcode = (lastcode == t) ? LM_TC_VAR : t; } } @@ -883,46 +962,48 @@ void MathCursor::handleAccent(string const & name, int code) MathDecorationInset * p = new MathDecorationInset(name, code); if (selection) { SelCut(); - p->cell(0) = selarray; + p->cell(0) = theSelection.glue(); } insert(p); push(p, true); } + void MathCursor::handleDelim(int l, int r) { MathDelimInset * p = new MathDelimInset(l, r); if (selection) { SelCut(); - p->cell(0) = selarray; + p->cell(0) = theSelection.glue(); } insert(p); + plainLeft(); push(p, true); } void MathCursor::GetPos(int & x, int & y) { - x = xarray().xo() + xarray().pos2x(cursor_); + x = xarray().xo() + xarray().pos2x(cursor().pos_); y = xarray().yo(); } MathTextCodes MathCursor::nextCode() const { - return array().GetCode(cursor_); + return array().GetCode(cursor().pos_); } MathTextCodes MathCursor::prevCode() const { - return array().GetCode(cursor_ - 1); + return array().GetCode(cursor().pos_ - 1); } MathInset * MathCursor::par() const { - return par_; + return cursor().par_; } @@ -934,7 +1015,7 @@ InsetFormulaBase const * MathCursor::formula() int MathCursor::pos() const { - return cursor_; + return cursor().pos_; } @@ -970,30 +1051,26 @@ MathTextCodes MathCursor::getLastCode() const MathInset * MathCursor::enclosing(MathInsetTypes t, int & idx) const { - if (par_->GetType() == t) { - //lyxerr << "enclosing par is current\n"; - idx = idx_; - return par_; - } - for (int i = path_.size() - 1; i >= 0; --i) { - lyxerr << "checking level " << i << "\n"; - if (path_[i].par_->GetType() == t) { - idx = path_[i].idx_; - return path_[i].par_; + for (int i = Cursor_.size() - 1; i >= 0; --i) { + //lyxerr << "checking level " << i << "\n"; + if (Cursor_[i].par_->GetType() == t) { + idx = Cursor_[i].idx_; + return Cursor_[i].par_; } } return 0; } + void MathCursor::pullArg() { // pullArg + dump("pullarg"); MathArray a = array(); - if (!Left()) - return; - normalize(); - array().erase(cursor_); - array().insert(cursor_, a); + if (pop()) { + array().erase(cursor().pos_); + array().insert(cursor().pos_, a); + } } @@ -1010,38 +1087,38 @@ void MathCursor::normalize() const #endif MathCursor * it = const_cast(this); - if (idx_ < 0 || idx_ > par_->nargs()) + if (cursor().idx_ < 0 || cursor().idx_ > cursor().par_->nargs()) lyxerr << "this should not really happen - 1\n"; - it->idx_ = max(idx_, 0); - it->idx_ = min(idx_, par_->nargs()); + it->cursor().idx_ = max(cursor().idx_, 0); + it->cursor().idx_ = min(cursor().idx_, cursor().par_->nargs()); - if (cursor_ < 0 || cursor_ > array().size()) + if (cursor().pos_ < 0 || cursor().pos_ > array().size()) lyxerr << "this should not really happen - 2\n"; - it->cursor_ = max(cursor_, 0); - it->cursor_ = min(cursor_, array().size()); + it->cursor().pos_ = max(cursor().pos_, 0); + it->cursor().pos_ = min(cursor().pos_, array().size()); } int MathCursor::col() const { - return par_->col(idx_); + return par()->col(cursor().idx_); } int MathCursor::row() const { - return par_->row(idx_); + return par()->row(cursor().idx_); } /* -char MathIter::GetChar() const +char MathCursorPos::GetChar() const { - return array().GetChar(cursor_); + return array().GetChar(cursor().pos_); } -string MathIter::readString() +string MathCursorPos::readString() { string s; int code = nextCode(); @@ -1052,10 +1129,11 @@ string MathIter::readString() } */ + MathInset * MathCursor::prevInset() const { normalize(); - int c = cursor_; + int c = cursor().pos_; if (!array().prev(c)) return 0; return array().nextInset(c); @@ -1065,17 +1143,17 @@ MathInset * MathCursor::prevInset() const MathInset * MathCursor::nextInset() const { normalize(); - return array().nextInset(cursor_); + return array().nextInset(cursor().pos_); } MathUpDownInset * MathCursor::nearbyUpDownInset() const { normalize(); - MathInset * p = array().prevInset(cursor_); + MathInset * p = array().prevInset(cursor().pos_); if (p && p->isUpDownInset()) return static_cast(p); - p = array().nextInset(cursor_); + p = array().nextInset(cursor().pos_); if (p && p->isUpDownInset()) return static_cast(p); return 0; @@ -1085,80 +1163,84 @@ MathUpDownInset * MathCursor::nearbyUpDownInset() const MathArray & MathCursor::array() const { static MathArray dummy; - if (!par_) { + if (!cursor().par_) { lyxerr << "############ par_ not valid\n"; return dummy; } - if (idx_ < 0 || idx_ >= par_->nargs()) { - lyxerr << "############ idx_ " << idx_ << " not valid\n"; + if (cursor().idx_ < 0 || cursor().idx_ >= cursor().par_->nargs()) { + lyxerr << "############ idx_ " << cursor().idx_ << " not valid\n"; return dummy; } - return par_->cell(idx_); + return cursor().cell(); } MathXArray & MathCursor::xarray() const { - return par_->xcell(idx_); + return cursor().xcell(); } - bool MathCursor::nextIsInset() const { - return cursor_ < array().size() && MathIsInset(nextCode()); + return cursor().pos_ < array().size() && MathIsInset(nextCode()); } bool MathCursor::prevIsInset() const { - return cursor_ > 0 && MathIsInset(prevCode()); + return cursor().pos_ > 0 && MathIsInset(prevCode()); } int MathCursor::xpos() const { normalize(); - return xarray().pos2x(cursor_); + return xarray().pos2x(cursor().pos_); } + void MathCursor::gotoX(int x) { - cursor_ = xarray().x2pos(x); + cursor().pos_ = xarray().x2pos(x); } + void MathCursor::idxNext() { - par_->idxNext(idx_, cursor_); + cursor().par_->idxNext(cursor().idx_, cursor().pos_); } + void MathCursor::idxPrev() { - par_->idxPrev(idx_, cursor_); + cursor().par_->idxPrev(cursor().idx_, cursor().pos_); } + void MathCursor::splitCell() { - if (idx_ == par_->nargs() - 1) + if (cursor().idx_ == cursor().par_->nargs() - 1) return; MathArray ar = array(); - ar.erase(0, cursor_); - array().erase(cursor_, array().size()); - ++idx_; - cursor_ = 0; + ar.erase(0, cursor().pos_); + array().erase(cursor().pos_, array().size()); + ++cursor().idx_; + cursor().pos_ = 0; array().insert(0, ar); } + void MathCursor::breakLine() { MathMatrixInset * p = static_cast(formula()->par()); if (p->GetType() == LM_OT_SIMPLE || p->GetType() == LM_OT_EQUATION) { p->mutate(LM_OT_EQNARRAY); - p->addRow(row()); - idx_ = p->nrows(); - cursor_ = 0; + p->addRow(0); + cursor().idx_ = p->nrows(); + cursor().pos_ = 0; } else { p->addRow(row()); @@ -1173,10 +1255,11 @@ void MathCursor::breakLine() // split cell splitCell(); - p->cell(idx_).swap(p->cell(idx_ + p->ncols() - 1)); + p->cell(cursor().idx_).swap(p->cell(cursor().idx_ + p->ncols() - 1)); } } + char MathCursor::valign() const { int idx; @@ -1185,6 +1268,7 @@ char MathCursor::valign() const return p ? p->valign() : 0; } + char MathCursor::halign() const { int idx; @@ -1192,3 +1276,125 @@ char MathCursor::halign() const static_cast(enclosing(LM_OT_MATRIX, idx)); return p ? p->halign(idx % p->ncols()) : 0; } + + +MathCursorPos MathCursor::firstSelectionPos() const +{ + MathCursorPos anc = normalAnchor(); + return anc < cursor() ? anc : cursor(); +} + + +MathCursorPos MathCursor::lastSelectionPos() const +{ + MathCursorPos anc = normalAnchor(); + return anc < cursor() ? cursor() : anc; +} + + +void MathCursor::getSelection(MathCursorPos & i1, MathCursorPos & i2) const +{ + MathCursorPos anc = normalAnchor(); + if (anc < cursor()) { + i1 = anc; + i2 = cursor(); + } else { + i1 = cursor(); + i2 = anc; + } +} + + +MathCursorPos & MathCursor::cursor() +{ + return Cursor_.back(); +} + + +MathCursorPos const & MathCursor::cursor() const +{ + return Cursor_.back(); +} + + + +//////////////////////////////////////////////////////////////////////// + + +bool operator==(MathCursorPos const & ti, MathCursorPos const & it) +{ + return ti.par_ == it.par_ && ti.idx_ == it.idx_ && ti.pos_ == it.pos_; +} + + +bool operator<(MathCursorPos const & ti, MathCursorPos const & it) +{ + if (ti.par_ != it.par_) { + lyxerr << "can't compare cursor and anchor in different insets\n"; + return true; + } + if (ti.idx_ != it.idx_) + return ti.idx_ < it.idx_; + return ti.pos_ < it.pos_; +} + + +MathArray & MathCursorPos::cell(int idx) const +{ + return par_->cell(idx); +} + +MathArray & MathCursorPos::cell() const +{ + return par_->cell(idx_); +} + + +MathXArray & MathCursorPos::xcell(int idx) const +{ + return par_->xcell(idx); +} + + +MathXArray & MathCursorPos::xcell() const +{ + return par_->xcell(idx_); +} + + +MathCursorPos MathCursor::normalAnchor() const +{ + // use Anchor on the same level as Cursor + MathCursorPos normal = Anchor_[Cursor_.size() - 1]; + if (Cursor_.size() < Anchor_.size() && !(normal < cursor())) { + // anchor is behind cursor -> move anchor behind the inset + normal.cell().next(normal.pos_); + } + //lyxerr << "normalizing: from " << Anchor_[Anchor_.size() - 1] << " to " + // << normal << "\n"; + return normal; +} + + +bool MathCursorPos::idxUp() +{ + return par_->idxUp(idx_, pos_); +} + + +bool MathCursorPos::idxDown() +{ + return par_->idxDown(idx_, pos_); +} + + +bool MathCursorPos::idxLeft() +{ + return par_->idxLeft(idx_, pos_); +} + + +bool MathCursorPos::idxRight() +{ + return par_->idxRight(idx_, pos_); +}