+
+
+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();
+}
+
+
+int MathCursor::cellXOffset() const
+{
+ return par()->cellXOffset(idx());
+}
+
+
+int MathCursor::cellYOffset() const
+{
+ return par()->cellYOffset(idx());
+}
+
+
+int MathCursor::xpos() const
+{
+ return cellXOffset() + xarray().pos2x(pos());
+}
+
+
+int MathCursor::ypos() const
+{
+ return cellYOffset();
+}
+
+
+
+void MathCursor::gotoX(int x)
+{
+ pos() = xarray().x2pos(x - cellXOffset());
+}
+
+
+bool MathCursor::goUp()
+{
+ // first ask the inset if it knows better then we
+ if (par()->idxUp(idx(), pos()))
+ return true;
+
+ // leave subscript to the nearest side
+ MathScriptInset * p = par()->asScriptInset();
+ if (p && p->hasDown()) {
+ if (pos() <= size() / 2)
+ popLeft();
+ else
+ popRight();
+ return true;
+ }
+
+ // if not, apply brute force.
+ int x0;
+ int y0;
+ getPos(x0, y0);
+ std::vector<MathCursorPos> save = Cursor_;
+ MathAtom const & out = formula()->par();
+ y0 -= xarray().ascent();
+ for (int y = y0 - 4; y > out->yo() - out->ascent(); y -= 4) {
+ setPos(x0, y);
+ if (save != Cursor_ && xarray().yo() < y0)
+ return true;
+ }
+ Cursor_ = save;
+ return false;
+}
+
+
+bool MathCursor::goDown()
+{
+ // first ask the inset if it knows better then we
+ if (par()->idxDown(idx(), pos()))
+ return true;
+
+ // leave superscript to the nearest side
+ MathScriptInset * p = par()->asScriptInset();
+ if (p && p->hasUp()) {
+ if (pos() <= size() / 2)
+ popLeft();
+ else
+ popRight();
+ return true;
+ }
+
+ // if not, apply brute force.
+ int x0;
+ int y0;
+ getPos(x0, y0);
+ std::vector<MathCursorPos> save = Cursor_;
+ MathAtom const & out = formula()->par();
+ y0 += xarray().descent();
+ for (int y = y0 + 4; y < out->yo() + out->descent(); y += 4) {
+ setPos(x0, y);
+ if (save != Cursor_ && xarray().yo() > y0)
+ return true;
+ }
+ Cursor_ = save;
+ return false;
+}
+
+
+bool MathCursor::idxLeft()
+{
+ return par()->idxLeft(idx(), pos());
+}
+
+
+bool MathCursor::idxRight()
+{
+ return par()->idxRight(idx(), pos());
+}
+
+
+void MathCursor::interpret(string const & s)
+{
+ //lyxerr << "interpret 1: '" << s << "'\n";
+ //lyxerr << "in: " << in_word_set(s) << " \n";
+
+ if (s.empty())
+ return;
+
+ if (s.size() == 1) {
+ interpret(s[0]);
+ return;
+ }
+
+ //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;
+
+ if (s.size() > 7 && s.substr(0, 7) == "matrix ") {
+ unsigned int m = 1;
+ unsigned int n = 1;
+ string v_align;
+ string h_align;
+ istringstream is(s.substr(7).c_str());
+ is >> m >> n >> v_align >> h_align;
+ m = std::max(1u, m);
+ n = std::max(1u, n);
+ v_align += 'c';
+ niceInsert(MathAtom(new MathArrayInset(m, n, v_align[0], h_align)));
+ return;
+ }
+
+ if (s == "\\over" || s == "\\choose" || s == "\\atop") {
+ MathArray ar = array();
+ MathAtom t = createMathInset(s.substr(1));
+ t->asNestInset()->cell(0).swap(array());
+ pos() = 0;
+ niceInsert(t);
+ popRight();
+ left();
+ return;
+ }
+
+ niceInsert(createMathInset(s.substr(1)));
+}
+
+
+void MathCursor::interpret(char c)
+{
+ //lyxerr << "interpret 2: '" << c << "'\n";
+
+ if (inMacroMode()) {
+ string name = macroName();
+
+ if (name == "\\" && c == '#') {
+ insert(c, LM_TC_TEX);
+ return;
+ }
+
+ if (name == "\\" && c == '\\') {
+ backspace();
+ interpret("\\backslash");
+ return;
+ }
+
+ if (name == "\\#" && '1' <= c && c <= '9') {
+ insert(c, LM_TC_TEX);
+ macroModeClose();
+ return;
+ }
+
+ if (isalpha(c)) {
+ insert(c, LM_TC_TEX);
+ return;
+ }
+
+ if (name == "\\") {
+ insert(c, LM_TC_TEX);
+ macroModeClose();
+ return;
+ }
+
+ macroModeClose();
+ return;
+ }
+
+ // no macro mode
+ if (c == '^' || c == '_') {
+ const bool up = (c == '^');
+ selCut();
+ if (hasPrevAtom() && prevAtom()->asScriptInset()) {
+ prevAtom()->asScriptInset()->ensure(up);
+ pushRight(prevAtom());
+ pos() = size();
+ } else if (hasNextAtom() && nextAtom()->asScriptInset()) {
+ nextAtom()->asScriptInset()->ensure(up);
+ pushLeft(nextAtom());
+ pos() = 0;
+ } else {
+ plainInsert(MathAtom(new MathScriptInset(up)));
+ pushRight(prevAtom());
+ }
+ idx() = up;
+ selPaste();
+ return;
+ }
+
+ if (selection_)
+ selDel();
+
+ if (lastcode_ == LM_TC_TEXTRM) {
+ insert(c, LM_TC_TEXTRM);
+ return;
+ }
+
+ if (c == ' ') {
+ if (hasPrevAtom() && prevAtom()->asSpaceInset()) {
+ prevAtom()->asSpaceInset()->incSpace();
+ return;
+ }
+
+ if (mathcursor->popRight())
+ return;
+
+#warning look here
+ // this would not work if the inset is in an table!
+ //bv->text->cursorRight(bv, true);
+ //result = FINISHED;
+ return;
+ }
+
+ if (strchr("{}", c)) {
+ insert(c, LM_TC_TEX);
+ return;
+ }
+
+ if (strchr("#$%", c)) {
+ insert(MathAtom(new MathSpecialCharInset(c)));
+ lastcode_ = LM_TC_VAR;
+ return;
+ }
+
+ if (isalpha(c) && (lastcode_ == LM_TC_GREEK || lastcode_ == LM_TC_GREEK1)) {
+ static char const greekl[][26] =
+ {"alpha", "beta", "chi", "delta", "epsilon", "phi",
+ "gamma", "eta", "iota", "epsilon", "kappa", "lambda", "mu",
+ "nu", "omikron", "pi", "vartheta", "rho", "sigma",
+ "tau", "upsilon", "theta", "omega", "xi", "varphi", "zeta"};
+ static char const greeku[][26] =
+ {"Alpha", "Beta", "chi", "Delta", "varepsilon", "Phi",
+ "Gamma", "Eta", "Iota", "Epsilon", "Kappa", "Lambda", "Mu",
+ "Nu", "Omikron", "Pi", "vartheta", "varrho", "Sigma", "varsigma",
+ "Upsilon", "Theta", "Omega", "Xi", "Varphi", "Zeta"};
+
+ latexkeys const * l = 0;
+ if ('a' <= c && c <= 'z')
+ l = in_word_set(greekl[c - 'a']);
+ if ('A' <= c && c <= 'Z')
+ l = in_word_set(greeku[c - 'A']);
+
+ if (l)
+ insert(createMathInset(l));
+ else
+ insert(c, LM_TC_VAR);
+
+#warning greek insert problem? look here!
+ if (lastcode_ == LM_TC_GREEK1)
+ lastcode_ = LM_TC_VAR;
+ return;
+ }
+
+ if (c == '\\') {
+ insert(c, LM_TC_TEX);
+ //bv->owner()->message(_("TeX mode"));
+ return;
+ }
+
+ // no special circumstances, so insert the character without any fuss
+ insert(c, LM_TC_MIN);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+
+
+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(MathCursor::idx_type idx) const
+{
+ return (*par_)->cell(idx);
+}
+
+
+MathArray & MathCursorPos::cell() const
+{
+ return (*par_)->cell(idx_);
+}
+
+
+MathXArray & MathCursorPos::xcell(MathCursor::idx_type 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.pos_;
+ }
+ return normal;
+}
+
+