*/
#include <config.h>
+#include <lyxrc.h>
#ifdef __GNUG__
#pragma implementation
#include "support/lstrings.h"
#include "support/LAssert.h"
+#include "BufferView.h"
#include "debug.h"
#include "LColor.h"
-#include "Painter.h"
+#include "frontends/Painter.h"
#include "math_cursor.h"
#include "formulabase.h"
+#include "funcrequest.h"
+#include "math_autocorrect.h"
#include "math_arrayinset.h"
#include "math_braceinset.h"
-#include "math_boxinset.h"
-#include "math_casesinset.h"
+#include "math_commentinset.h"
#include "math_charinset.h"
-#include "math_deliminset.h"
+#include "math_extern.h"
#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"
#include "math_scriptinset.h"
#include "math_spaceinset.h"
-#include "math_specialcharinset.h"
#include "math_support.h"
+#include "math_unknowninset.h"
#include <algorithm>
#include <cctype>
-#define FILEDEBUG 0
+//#define FILEDEBUG 1
using std::endl;
using std::min;
using std::max;
using std::swap;
-using std::isalnum;
+using std::vector;
+using std::ostringstream;
+using std::isalpha;
-namespace {
-
-struct Selection
-{
- typedef MathInset::col_type col_type;
- typedef MathInset::row_type row_type;
- typedef MathInset::idx_type idx_type;
-
- Selection()
- : data_(1, 1)
- {}
-
- void region(MathCursorPos const & i1, MathCursorPos const & i2,
- row_type & r1, row_type & r2, col_type & c1, col_type & c2)
- {
- MathInset * p = i1.par_;
- c1 = p->col(i1.idx_);
- c2 = p->col(i2.idx_);
- if (c1 > c2)
- std::swap(c1, c2);
- r1 = p->row(i1.idx_);
- r2 = p->row(i2.idx_);
- if (r1 > r2)
- std::swap(r1, r2);
- }
-
- void grab(MathCursor const & cursor)
- {
- MathCursorPos i1;
- MathCursorPos i2;
- cursor.getSelection(i1, i2);
- // shouldn'tt we assert on i1.par_ == i2.par_?
- if (i1.idx_ == i2.idx_) {
- data_ = MathGridInset(1, 1);
- data_.cell(0) = MathArray(i1.cell(), i1.pos_, i2.pos_);
- } else {
- row_type r1, r2;
- col_type 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 (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);
- }
- }
- }
-
- 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 {
- 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)
- for (col_type col = c1; col <= c2; ++col)
- p->cell(p->index(row, col)).erase();
- }
- cursor.cursor() = i1;
- }
-
- void paste(MathCursor & cursor) const
- {
- idx_type idx;
- 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 (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)));
- }
- }
-
- // glues selection to one cell
- MathArray glue() const
- {
- MathArray ar;
- for (unsigned i = 0; i < data_.nargs(); ++i)
- ar.push_back(data_.cell(i));
- return ar;
- }
-
- void clear()
- {
- data_ = MathGridInset(1, 1);
- }
-
- MathGridInset data_;
-};
-
-
-Selection theSelection;
+// matheds own cut buffer
+MathGridInset theCutBuffer = MathGridInset(1, 1);
+MathCursor::MathCursor(InsetFormulaBase * formula, bool front)
+ : formula_(formula), autocorrect_(false), selection_(false)
+{
+ front ? first() : last();
+ Anchor_ = Cursor_;
}
-MathCursor::MathCursor(InsetFormulaBase * formula, bool left)
- : formula_(formula), lastcode_(LM_TC_VAR), selection_(false)
+MathCursor::~MathCursor()
{
- left ? first() : last();
+ // ensure that 'notifyCursorLeave' is called
+ while (popLeft())
+ ;
}
void MathCursor::pushLeft(MathAtom & t)
{
- //cerr << "Entering atom "; t->write(cerr, false); cerr << " left\n";
+ //lyxerr << "Entering atom " << t << " left\n";
push(t);
t->idxFirst(idx(), pos());
}
void MathCursor::pushRight(MathAtom & t)
{
- //cerr << "Entering atom "; t->write(cerr, false); cerr << " right\n";
+ //lyxerr << "Entering atom " << t << " right\n";
posLeft();
push(t);
t->idxLast(idx(), pos());
bool MathCursor::popLeft()
{
- //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " left\n";
- if (Cursor_.size() <= 1)
+ //cerr << "Leaving atom to the left\n";
+ if (depth() <= 1) {
+ if (depth() == 1)
+ par()->notifyCursorLeaves();
return false;
- if (par()->asScriptInset())
- par()->asScriptInset()->removeEmptyScripts();
+ }
+ par()->notifyCursorLeaves();
Cursor_.pop_back();
return true;
}
bool MathCursor::popRight()
{
//cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n";
- if (Cursor_.size() <= 1)
+ if (depth() <= 1) {
+ if (depth() == 1)
+ par()->notifyCursorLeaves();
return false;
- if (par()->asScriptInset())
- par()->asScriptInset()->removeEmptyScripts();
+ }
+ par()->notifyCursorLeaves();
Cursor_.pop_back();
posRight();
return true;
void MathCursor::dump(char const * what) const
{
lyxerr << "MC: " << what << "\n";
- lyxerr << " Cursor: " << Cursor_.size() << "\n";
- for (unsigned i = 0; i < Cursor_.size(); ++i)
+ lyxerr << " Cursor: " << depth() << "\n";
+ for (unsigned i = 0; i < depth(); ++i)
lyxerr << " i: " << i << " " << Cursor_[i] << "\n";
lyxerr << " Anchor: " << Anchor_.size() << "\n";
for (unsigned i = 0; i < Anchor_.size(); ++i)
#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 < depth(); ++i)
+ if (Cursor_[i].par_ == p)
return true;
return false;
}
bool MathCursor::openable(MathAtom const & t, bool sel) const
{
- if (t->isHyperActive())
- return true;
-
if (!t->isActive())
return false;
- if (t->asScriptInset())
+ if (t->lock())
return false;
if (sel) {
// we can't move into anything new during selection
- if (Cursor_.size() == Anchor_.size())
+ if (depth() == Anchor_.size())
return false;
- if (t.nucleus() != Anchor_[Cursor_.size()].par_)
+ if (t.operator->() != Anchor_[depth()].par_)
return false;
}
return true;
}
+bool MathCursor::inNucleus() const
+{
+ return par()->asScriptInset() && idx() == 2;
+}
+
+
bool MathCursor::posLeft()
{
if (pos() == 0)
bool MathCursor::left(bool sel)
{
dump("Left 1");
+ autocorrect_ = false;
+ targetx_ = -1; // "no target"
if (inMacroMode()) {
macroModeClose();
- lastcode_ = LM_TC_VAR;
return true;
}
selHandle(sel);
- lastcode_ = LM_TC_VAR;
if (hasPrevAtom() && openable(prevAtom(), sel)) {
- if (prevAtom()->isHyperActive()) {
- lyxerr << "entering hyperactive inset\n";
- }
pushRight(prevAtom());
return true;
- }
+ }
return posLeft() || idxLeft() || popLeft() || selection_;
}
bool MathCursor::right(bool sel)
{
dump("Right 1");
+ autocorrect_ = false;
+ targetx_ = -1; // "no target"
if (inMacroMode()) {
macroModeClose();
- lastcode_ = LM_TC_VAR;
return true;
}
selHandle(sel);
- lastcode_ = LM_TC_VAR;
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;
}
void MathCursor::first()
{
Cursor_.clear();
- pushLeft(formula_->par());
+ push(formula_->par());
+ par()->idxFirst(idx(), pos());
}
void MathCursor::last()
{
- first();
- end();
+ Cursor_.clear();
+ push(formula_->par());
+ par()->idxLast(idx(), pos());
}
-bool positionable(MathCursor::cursor_type const & cursor,
- MathCursor::cursor_type const & anchor)
+bool positionable(MathIterator const & cursor, MathIterator const & anchor)
{
// avoid deeper nested insets when selecting
if (cursor.size() > anchor.size())
return false;
// anchor might be deeper, should have same path then
- for (MathCursor::cursor_type::size_type i = 0; i < cursor.size(); ++i)
+ for (MathIterator::size_type i = 0; i < cursor.size(); ++i)
if (cursor[i].par_ != anchor[i].par_)
return false;
formula()->xlow(), formula()->xhigh(),
formula()->ylow(), formula()->yhigh());
if (!res) {
- // this ccan happen on creation of "math-display"
+ // this can happen on creation of "math-display"
dump("setPos 1.5");
first();
}
+ targetx_ = -1; // "no target"
dump("setPos 2");
}
-void MathCursor::home(bool sel)
+bool MathCursor::home(bool sel)
{
dump("home 1");
+ autocorrect_ = false;
selHandle(sel);
macroModeClose();
- lastcode_ = LM_TC_VAR;
- if (!par()->idxHome(idx(), pos()))
- popLeft();
+ if (!par()->idxHome(idx(), pos()))
+ return popLeft();
dump("home 2");
+ targetx_ = -1; // "no target"
+ return true;
}
-void MathCursor::end(bool sel)
+bool MathCursor::end(bool sel)
{
dump("end 1");
+ autocorrect_ = false;
selHandle(sel);
macroModeClose();
- lastcode_ = LM_TC_VAR;
if (!par()->idxEnd(idx(), pos()))
- popRight();
+ return popRight();
dump("end 2");
+ targetx_ = -1; // "no target"
+ return true;
}
}
+void MathCursor::markInsert()
+{
+ //lyxerr << "inserting mark\n";
+ array().insert(pos(), MathAtom(new MathCharInset(0)));
+}
+
+
+void MathCursor::markErase()
+{
+ //lyxerr << "deleting mark\n";
+ array().erase(pos());
+}
+
+
void MathCursor::plainInsert(MathAtom const & t)
{
+ dump("plainInsert");
array().insert(pos(), t);
++pos();
}
-void MathCursor::insert(char c, MathTextCodes t)
+void MathCursor::insert(string const & str)
+{
+ //lyxerr << "inserting '" << str << "'\n";
+ selClearOrDel();
+ for (string::const_iterator it = str.begin(); it != str.end(); ++it)
+ plainInsert(MathAtom(new MathCharInset(*it)));
+}
+
+
+void MathCursor::insert(char c)
{
//lyxerr << "inserting '" << c << "'\n";
- plainInsert(MathAtom(new MathCharInset(c, t)));
+ selClearOrDel();
+ plainInsert(MathAtom(new MathCharInset(c)));
}
void MathCursor::insert(MathAtom const & t)
{
macroModeClose();
-
- if (selection_) {
- 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!
- MathAtom const & p = prevAtom();
- if (p->nargs()) {
+ macroModeClose();
+ MathGridInset safe = grabAndEraseSelection();
+ plainInsert(t);
+ // enter the new inset and move the contents of the selection if possible
+ if (t->isActive()) {
posLeft();
- right(); // do not push for e.g. MathSymbolInset
- selPaste();
+ pushLeft(nextAtom());
+ paste(safe);
}
}
{
macroModeClose();
if (selection_)
- selCut();
+ eraseSelection();
array().insert(pos(), ar);
pos() += ar.size();
}
+void MathCursor::paste(MathGridInset const & data)
+{
+ ostringstream os;
+ WriteStream wi(os, false, false);
+ data.write(wi);
+ dispatch(FuncRequest(LFUN_PASTE, os.str()));
+}
+
+
void MathCursor::backspace()
{
+ autocorrect_ = false;
if (pos() == 0) {
- pullArg(false);
+ pullArg();
return;
- }
+ }
if (selection_) {
selDel();
return;
}
- MathScriptInset * p = prevAtom()->asScriptInset();
- if (p) {
- p->removeScript(p->hasUp());
- // Don't delete if there is anything left
- if (p->hasUp() || p->hasDown())
+ if (inMacroMode()) {
+ MathUnknownInset * p = activeMacro();
+ if (p->name().size() > 1) {
+ p->setName(p->name().substr(0, p->name().size() - 1));
return;
+ }
+ }
+
+/*
+ if (prevAtom()->asScriptInset()) {
+ // simply enter nucleus
+ left();
+ return;
+ }
+
+ if (inNucleus()) {
+ // we are in nucleus
+ if (pos() == 1) {
+ }
}
+*/
--pos();
plainErase();
void MathCursor::erase()
{
+ autocorrect_ = false;
if (inMacroMode())
return;
return;
}
- // delete empty cells if necessary
- if (array().empty()) {
- bool popit;
- bool removeit;
- par()->idxDelete(idx(), popit, removeit);
- if (popit && popLeft() && removeit)
- plainErase();
- return;
- }
-
- if (pos() == size())
- return;
-
- MathScriptInset * p = nextAtom()->asScriptInset();
- if (p) {
- p->removeScript(p->hasUp());
- // Don't delete if there is anything left
- if (p->hasUp() || p->hasDown())
+ // delete empty cells if possible
+ if (array().empty())
+ if (par()->idxDelete(idx()))
return;
- }
- plainErase();
-}
-
-
-void MathCursor::delLine()
-{
- macroModeClose();
-
- if (selection_) {
- selDel();
+ // old behaviour when in last position of cell
+ if (pos() == size()) {
+ par()->idxGlue(idx());
return;
}
- if (par()->nrows() > 1) {
- // grid are the only things with more than one row...
- lyx::Assert(par()->asGridInset());
- par()->asGridInset()->delRow(hullRow());
+/*
+ // if we are standing in front of a script inset, grab item before us and
+ // move it into nucleus
+ // and remove first thing.
+ if (hasNextAtom() && nextAtom()->asScriptInset()) {
+ if (hasPrevAtom()) {
+ MathAtom at = prevAtom();
+ --pos();
+ array().erase(pos());
+ pushLeft(nextAtom());
+ if (array().empty())
+ array().push_back(at);
+ else
+ array()[0] = at;
+ pos() = 1;
+ } else {
+ pushLeft(nextAtom());
+ array().clear();
+ }
+ return;
}
+*/
- if (idx() > par()->nargs())
- idx() = par()->nargs();
-
- if (pos() > size())
- pos() = size();
+ plainErase();
}
dump("up 1");
macroModeClose();
selHandle(sel);
- cursor_type save = Cursor_;
+ MathIterator save = Cursor_;
if (goUpDown(true))
return true;
Cursor_ = save;
+ autocorrect_ = false;
return selection_;
}
dump("down 1");
macroModeClose();
selHandle(sel);
- cursor_type save = Cursor_;
+ MathIterator save = Cursor_;
if (goUpDown(false))
return true;
Cursor_ = save;
+ autocorrect_ = false;
return selection_;
}
bool MathCursor::toggleLimits()
{
- if (!hasNextAtom())
- return false;
- MathScriptInset * t = nextAtom()->asScriptInset();
- if (!t)
+ if (!hasNextAtom() || !nextAtom()->asScriptInset())
return false;
+ MathScriptInset * t = nextAtom().nucleus()->asScriptInset();
int old = t->limits();
t->limits(old < 0 ? 1 : -1);
return old != t->limits();
void MathCursor::macroModeClose()
{
- string s = macroName();
- if (s.size()) {
- size_type old = pos();
- pos() -= s.size();
- array().erase(pos(), old);
+ if (!inMacroMode())
+ return;
+ MathUnknownInset * p = activeMacro();
+ p->finalize();
+ string s = p->name();
+ --pos();
+ array().erase(pos());
+ if (s != "\\")
interpret(s);
- }
}
-int MathCursor::macroNamePos() const
+string MathCursor::macroName() const
{
- for (int i = pos() - 1; i >= 0; --i) {
- MathAtom & p = array().at(i);
- if (p->code() == LM_TC_TEX && p->getChar() == '\\')
- return i;
- }
- return -1;
+ return inMacroMode() ? activeMacro()->name() : string();
}
-string MathCursor::macroName() const
+void MathCursor::selClear()
{
- string s;
- for (int i = macroNamePos(); i >= 0 && i < int(pos()); ++i)
- s += array().at(i)->getChar();
- return s;
+ Anchor_.clear();
+ selection_ = false;
}
{
dump("selCopy");
if (selection_) {
- theSelection.grab(*this);
- selClear();
+ theCutBuffer = grabSelection();
+ selection_ = false;
+ } else {
+ theCutBuffer = MathGridInset(1, 1);
}
}
void MathCursor::selCut()
{
dump("selCut");
- if (selection_) {
- theSelection.grab(*this);
- theSelection.erase(*this);
- selClear();
- } else {
- theSelection.clear();
- }
+ theCutBuffer = grabAndEraseSelection();
}
{
dump("selDel");
if (selection_) {
- theSelection.erase(*this);
- if (pos() > size())
- pos() = size();
- selClear();
+ eraseSelection();
+ selection_ = false;
}
}
void MathCursor::selPaste()
{
dump("selPaste");
- theSelection.paste(*this);
- //theSelection.grab(*this);
- //selClear();
+ selClearOrDel();
+ paste(theCutBuffer);
+ //grabSelection();
+ selection_ = false;
}
{
if (sel == selection_)
return;
- //theSelection.clear();
- Anchor_ = Cursor_;
+ //clear();
+ Anchor_ = Cursor_;
selection_ = sel;
}
void MathCursor::selStart()
{
dump("selStart 1");
- //theSelection.clear();
+ //clear();
Anchor_ = Cursor_;
selection_ = true;
dump("selStart 2");
}
-void MathCursor::selClear()
+void MathCursor::selClearOrDel()
{
- dump("selClear 1");
- selection_ = false;
- dump("selClear 2");
+ if (lyxrc.auto_region_delete)
+ selDel();
+ else
+ selection_ = false;
}
void MathCursor::selGet(MathArray & ar)
{
dump("selGet");
- if (!selection_)
- return;
-
- theSelection.grab(*this);
- ar = theSelection.glue();
+ if (selection_)
+ ar = grabSelection().glue();
}
-
-void MathCursor::drawSelection(Painter & pain) const
+void MathCursor::drawSelection(MathPainterInfo & pi) const
{
if (!selection_)
return;
-
MathCursorPos i1;
MathCursorPos i2;
getSelection(i1, i2);
-
- 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 {
- std::vector<MathInset::idx_type> 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);
- }
- }
-
-#if 0
- // draw anchor if different from selection boundary
- MathCursorPos anc = Anchor_.back();
- if (anc != i1 && anc != i2) {
- MathXArray & c = anc.xcell();
- int x = c.xo() + c.pos2x(anc.pos_);
- int y1 = c.yo() - c.ascent();
- int y2 = c.yo() + c.descent();
- pain.line(x, y1, x, y2, LColor::math);
- }
-#endif
-}
-
-
-void MathCursor::handleFont(MathTextCodes t)
-{
- macroModeClose();
- if (selection_) {
- MathCursorPos i1;
- MathCursorPos 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
- lastcode_ = (lastcode_ == t) ? LM_TC_VAR : t;
+ i1.par_->drawSelection(pi, i1.idx_, i1.pos_, i2.idx_, i2.pos_);
}
-void MathCursor::handleDelim(string const & l, string const & r)
+void MathCursor::handleNest(MathAtom const & a)
{
- handleNest(new MathDelimInset(l, r));
+ MathAtom at = a;
+ at.nucleus()->cell(0) = grabAndEraseSelection().glue();
+ insert(at);
+ pushRight(prevAtom());
}
-void MathCursor::handleNest(MathInset * p)
+void MathCursor::getPos(int & x, int & y) const
{
- if (selection_) {
- selCut();
- p->cell(0) = theSelection.glue();
- }
- insert(MathAtom(p)); // this invalidates p!
- pushRight(prevAtom());
+ par()->getPos(idx(), pos(), x, y);
}
-void MathCursor::getPos(int & x, int & y)
+int MathCursor::targetX() const
{
-#ifdef WITH_WARNINGS
-#warning This should probably take cellXOffset and cellYOffset into account
-#endif
- x = xarray().xo() + xarray().pos2x(pos());
- y = xarray().yo();
+ if (targetx_ != -1)
+ return targetx_;
+ int x = 0, y = 0;
+ getPos(x, y);
+ return x;
}
}
-InsetFormulaBase * MathCursor::formula()
+InsetFormulaBase * MathCursor::formula() const
{
return formula_;
}
bool MathCursor::inMacroMode() const
{
- return macroNamePos() != -1;
+ if (!hasPrevAtom())
+ return false;
+ MathUnknownInset const * p = prevAtom()->asUnknownInset();
+ return p && !p->final();
+}
+
+
+MathUnknownInset * MathCursor::activeMacro()
+{
+ return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
+}
+
+
+MathUnknownInset const * MathCursor::activeMacro() const
+{
+ return inMacroMode() ? prevAtom()->asUnknownInset() : 0;
+}
+
+
+bool MathCursor::inMacroArgMode() const
+{
+ return pos() > 0 && prevAtom()->getChar() == '#';
}
MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const
{
- for (int i = Cursor_.size() - 1; i >= 0; --i) {
+ for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
MathGridInset * p = Cursor_[i].par_->asGridInset();
if (p) {
idx = Cursor_[i].idx_;
}
-void MathCursor::pullArg(bool goright)
+void MathCursor::popToHere(MathInset const * p)
{
- dump("pullarg");
- MathArray a = array();
+ while (depth() && Cursor_.back().par_ != p)
+ Cursor_.pop_back();
+}
- MathScriptInset const * p = par()->asScriptInset();
- if (p) {
- // special handling for scripts
- const bool up = p->hasUp();
- popLeft();
- MathScriptInset * q = nextAtom()->asScriptInset();
- if (q)
- q->removeScript(up);
- ++pos();
- array().insert(pos(), a);
- return;
- }
+void MathCursor::popToEnclosingGrid()
+{
+ while (depth() && !Cursor_.back().par_->asGridInset())
+ Cursor_.pop_back();
+}
+
+
+void MathCursor::popToEnclosingHull()
+{
+ while (depth() && !Cursor_.back().par_->asHullInset())
+ Cursor_.pop_back();
+}
+
+
+void MathCursor::pullArg()
+{
+ dump("pullarg");
+ MathArray a = array();
if (popLeft()) {
plainErase();
array().insert(pos(), a);
- if (goright)
- pos() += a.size();
+ Anchor_ = Cursor_;
+ } else {
+ formula()->mutateToText();
}
}
-void MathCursor::normalize()
+void MathCursor::touch()
{
- // rebreak
- {
- MathIterator it = ibegin(formula()->par().nucleus());
- MathIterator et = iend(formula()->par().nucleus());
- for ( ; it != et; ++it)
- if (it.par()->asBoxInset())
- it.par()->asBoxInset()->rebreak();
- }
+ MathIterator::const_iterator it = Cursor_.begin();
+ MathIterator::const_iterator et = Cursor_.end();
+ for ( ; it != et; ++it)
+ it->cell().touch();
+}
- if (idx() >= par()->nargs()) {
+
+void MathCursor::normalize()
+{
+ if (idx() >= par()->nargs()) {
lyxerr << "this should not really happen - 1: "
- << idx() << " " << par()->nargs() << "\n";
+ << idx() << " " << par()->nargs() << " in: " << par() << "\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());
-}
-
-
-MathCursor::size_type MathCursor::size() const
-{
- return array().size();
-}
+ // remove empty scripts if possible
+ if (1) {
+ for (pos_type i = 0; i < size(); ++i) {
+ MathScriptInset * p = array()[i].nucleus()->asScriptInset();
+ if (p) {
+ p->removeEmptyScripts();
+ //if (p->empty())
+ // array().erase(i);
+ }
+ }
+ }
-MathCursor::col_type MathCursor::hullCol() const
-{
- return Cursor_[0].par_->asGridInset()->col(Cursor_[0].idx_);
+ // fix again position
+ pos() = min(pos(), size());
}
-MathCursor::row_type MathCursor::hullRow() const
+MathCursor::size_type MathCursor::size() const
{
- return Cursor_[0].par_->asGridInset()->row(Cursor_[0].idx_);
+ return array().size();
}
MathAtom const & MathCursor::prevAtom() const
{
lyx::Assert(pos() > 0);
- return array().at(pos() - 1);
+ return array()[pos() - 1];
}
MathAtom & MathCursor::prevAtom()
{
lyx::Assert(pos() > 0);
- return array().at(pos() - 1);
+ return array()[pos() - 1];
}
MathAtom const & MathCursor::nextAtom() const
{
lyx::Assert(pos() < size());
- return array().at(pos());
+ return array()[pos()];
}
MathAtom & MathCursor::nextAtom()
{
lyx::Assert(pos() < size());
- return array().at(pos());
+ return array()[pos()];
}
return dummy;
}
- if (Cursor_.size() == 0) {
- lyxerr << "############ Cursor_.size() == 0 not valid\n";
+ if (depth() == 0) {
+ lyxerr << "############ depth() == 0 not valid\n";
return dummy;
}
}
-MathXArray & MathCursor::xarray() const
-{
- static MathXArray dummy;
-
- if (Cursor_.size() == 0) {
- lyxerr << "############ Cursor_.size() == 0 not valid\n";
- return dummy;
- }
-
- return cursor().xcell();
-}
-
-
void MathCursor::idxNext()
{
par()->idxNext(idx(), pos());
}
-void MathCursor::splitCell()
-{
- if (idx() + 1 == par()->nargs())
- return;
- MathArray ar = array();
- ar.erase(0, pos());
- array().erase(pos(), size());
- ++idx();
- pos() = 0;
- array().insert(0, ar);
-}
-
-
-void MathCursor::breakLine()
-{
- // leave inner cells
- while (popRight())
- ;
-
- MathHullInset * p = formula()->par()->asHullInset();
- if (!p)
- return;
-
- if (p->getType() == LM_OT_SIMPLE || p->getType() == LM_OT_EQUATION) {
- p->mutate(LM_OT_EQNARRAY);
- idx() = 0;
- pos() = size();
- } else {
- p->addRow(hullRow());
-
- // split line
- const row_type r = hullRow();
- for (col_type c = hullCol() + 1; c < p->ncols(); ++c)
- p->cell(p->index(r, c)).swap(p->cell(p->index(r + 1, c)));
-
- // split cell
- splitCell();
- p->cell(idx()).swap(p->cell(idx() + p->ncols() - 1));
- }
-}
-
-
-//void MathCursor::readLine(MathArray & ar) const
-//{
-// idx_type base = row() * par()->ncols();
-// for (idx_type off = 0; off < par()->ncols(); ++off)
-// ar.push_back(par()->cell(base + off));
-//}
-
-
char MathCursor::valign() const
{
idx_type idx;
MathCursorPos & MathCursor::cursor()
{
- lyx::Assert(Cursor_.size());
+ lyx::Assert(depth());
return Cursor_.back();
}
MathCursorPos const & MathCursor::cursor() const
{
- lyx::Assert(Cursor_.size());
+ lyx::Assert(depth());
return Cursor_.back();
}
bool MathCursor::goUpDown(bool up)
{
- int xlow, xhigh, ylow, yhigh;
-
- int xo, yo;
+ // 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 xo = 0;
+ int yo = 0;
getPos(xo, yo);
- // try current cell first
- xarray().boundingBox(xlow, xhigh, ylow, yhigh);
- if (up)
- yhigh = yo - 4;
+ // check if we had something else in mind, if not, this is the future goal
+ if (targetx_ == -1)
+ targetx_ = xo;
else
- ylow = yo + 4;
- if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh))
- return true;
+ xo = targetx_;
+
+ // try neigbouring script insets
+ // try left
+ if (hasPrevAtom()) {
+ MathScriptInset const * 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 const * 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(), pos(), up, targetx_))
+ return true;
- if (!popLeft()) {
- // no such inset found, just take something "above"
+ // no such inset found, just take something "above"
+ ///lyxerr << "updown: handled by strange case\n";
+ if (!popLeft())
return
bruteFind(xo, yo,
formula()->xlow(),
up ? formula()->ylow() : yo + 4,
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;
+ MathIterator 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, Anchor_)) {
+ int xo, yo;
+ it.back().getPos(xo, yo);
+ 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;
+ }
}
}
+
+ if (it == et)
+ break;
+ ++it;
}
+
if (best_dist < 1e10)
Cursor_ = best_cursor;
return best_dist < 1e10;
}
+bool MathCursor::idxLineLast()
+{
+ idx() -= idx() % par()->ncols();
+ idx() += par()->ncols() - 1;
+ pos() = size();
+ return true;
+}
+
bool MathCursor::idxLeft()
{
return par()->idxLeft(idx(), pos());
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()->getTransManager().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);
- niceInsert(MathAtom(new MathCasesInset(n)));
- return true;
- }
-
if (s.size() >= 6 && s.substr(0, 6) == "matrix") {
unsigned int m = 1;
unsigned int n = 1;
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;
}
return true;
}
- if (s == "\\over" || s == "\\choose" || s == "\\atop") {
- MathArray ar = array();
- MathAtom t(createMathInset(s.substr(1)));
- t->asNestInset()->cell(0).swap(array());
+ string name = s.substr(1);
+
+ if (name == "over" || name == "choose" || name == "atop") {
+ MathAtom t(createMathInset(name));
+ t.nucleus()->asNestInset()->cell(0) = array();
+ array().clear();
pos() = 0;
niceInsert(t);
popRight();
return true;
}
- latexkeys const * l = in_word_set(s.substr(1));
- if (l && (l->token == LM_TK_FONT || l->token == LM_TK_OLDFONT)) {
- lastcode_ = static_cast<MathTextCodes>(l->id);
+ // 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(s.substr(1)));
+ niceInsert(createMathInset(name));
return true;
}
+
bool MathCursor::script(bool up)
{
+ // Hack to get \\^ and \\_ working
+ if (inMacroMode() && macroName() == "\\") {
+ if (up)
+ niceInsert(createMathInset("mathcircumflex"));
+ else
+ interpret('_');
+ return true;
+ }
+
macroModeClose();
- selCut();
- if (hasPrevAtom() && prevAtom()->asScriptInset()) {
- prevAtom()->asScriptInset()->ensure(up);
+ MathGridInset safe = grabAndEraseSelection();
+ if (inNucleus()) {
+ // we are in a nucleus of a script inset, move to _our_ script
+ par()->asScriptInset()->ensure(up);
+ idx() = up;
+ pos() = 0;
+ } else if (hasPrevAtom() && prevAtom()->asScriptInset()) {
+ prevAtom().nucleus()->asScriptInset()->ensure(up);
pushRight(prevAtom());
idx() = up;
pos() = size();
- } else if (hasNextAtom() && nextAtom()->asScriptInset()) {
- nextAtom()->asScriptInset()->ensure(up);
+ } else if (hasPrevAtom()) {
+ --pos();
+ array()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up));
pushLeft(nextAtom());
idx() = up;
pos() = 0;
} else {
plainInsert(MathAtom(new MathScriptInset(up)));
- prevAtom()->asScriptInset()->ensure(up);
+ prevAtom().nucleus()->asScriptInset()->ensure(up);
pushRight(prevAtom());
idx() = up;
pos() = 0;
}
- selPaste();
+ paste(safe);
dump("1");
return true;
}
bool MathCursor::interpret(char c)
{
//lyxerr << "interpret 2: '" << c << "'\n";
+ targetx_ = -1; // "no target"
+ if (inMacroArgMode()) {
+ --pos();
+ plainErase();
+ int n = c - '0';
+ MathMacroTemplate const * p = formula()->par()->asMacroTemplate();
+ if (p && 1 <= n && n <= p->numargs())
+ insert(MathAtom(new MathMacroArgument(c - '0')));
+ else {
+ insert(createMathInset("#"));
+ interpret(c); // try again
+ }
+ return true;
+ }
+
// handle macroMode
if (inMacroMode()) {
string name = macroName();
+ //lyxerr << "interpret name: '" << name << "'\n";
- if (name == "\\" && c == '#') {
- insert(c, LM_TC_TEX);
+ if (isalpha(c)) {
+ activeMacro()->setName(activeMacro()->name() + c);
return true;
}
- if (name == "\\" && c == '\\') {
+ // handle 'special char' macros
+ if (name == "\\") {
+ // remove the '\\'
backspace();
- interpret("\\backslash");
+ if (c == '\\') {
+ if (currentMode() == MathInset::TEXT_MODE)
+ niceInsert(createMathInset("textbackslash"));
+ else
+ niceInsert(createMathInset("backslash"));
+ } else
+ niceInsert(createMathInset(string(1, c)));
return true;
}
- if (name == "\\#" && '1' <= c && c <= '9') {
- insert(c, LM_TC_TEX);
- macroModeClose();
- return true;
- }
+ // leave macro mode and try again if necessary
+ macroModeClose();
+ if (c != ' ')
+ interpret(c);
+ return true;
+ }
- if (isalpha(c)) {
- insert(c, LM_TC_TEX);
- return true;
- }
+ // This is annoying as one has to press <space> far too often.
+ // Disable it.
- if (name == "\\") {
- insert(c, LM_TC_TEX);
- macroModeClose();
+ if (0) {
+ // leave autocorrect mode if necessary
+ if (autocorrect_ && c == ' ') {
+ autocorrect_ = false;
return true;
}
+ }
- macroModeClose();
+ // just clear selection on pressing the space bar
+ if (selection_ && c == ' ') {
+ selection_ = false;
return true;
}
- if (selection_) {
- selClear();
- if (c == ' ')
- return true;
- // fall through in the other cases
+ selClearOrDel();
+
+ if (c == '\\') {
+ //lyxerr << "starting with macro\n";
+ insert(MathAtom(new MathUnknownInset("\\", false)));
+ return true;
}
- if (lastcode_ == LM_TC_TEXTRM || par()->asBoxInset()) {
- // suppress direct insertion of two spaces in a row
- // the still allows typing '<space>a<space>' and deleting the 'a', but
- // it is better than nothing...
- if (c == ' ' && hasPrevAtom() && prevAtom()->getChar() == ' ')
- return true;
- insert(c, LM_TC_TEXTRM);
+ if (c == '\n') {
+ if (currentMode() == MathInset::TEXT_MODE)
+ insert(c);
return true;
}
if (c == ' ') {
+ if (currentMode() == MathInset::TEXT_MODE) {
+ // insert spaces in text mode,
+ // but suppress direct insertion of two spaces in a row
+ // the still allows typing '<space>a<space>' and deleting the 'a', but
+ // it is better than nothing...
+ if (!hasPrevAtom() || prevAtom()->getChar() != ' ')
+ insert(c);
+ return true;
+ }
if (hasPrevAtom() && prevAtom()->asSpaceInset()) {
- prevAtom()->asSpaceInset()->incSpace();
+ prevAtom().nucleus()->asSpaceInset()->incSpace();
return true;
}
if (popRight())
return pos() != size();
}
+ if (c == '#') {
+ insert(c); // LM_TC_TEX;
+ return true;
+ }
+
/*
- if (strchr("{}", c)) {
- insert(c, LM_TC_TEX);
+ if (c == '{' || c == '}', c)) {
+ insert(c); // LM_TC_TEX;
return true;
}
*/
return true;
}
- if (strchr("#$%", c)) {
- insert(MathAtom(new MathSpecialCharInset(c)));
- lastcode_ = LM_TC_VAR;
+ if (c == '$') {
+ insert(createMathInset("$"));
+ return true;
+ }
+
+ if (c == '%') {
+ niceInsert(MathAtom(new MathCommentInset));
return true;
}
+/*
if (isalpha(c) && lastcode_ == LM_TC_GREEK) {
insert(c, LM_TC_VAR);
return true;
if (c == '\\') {
insert(c, LM_TC_TEX);
//bv->owner()->message(_("TeX mode"));
- return true;
+ return true;
}
+*/
+
+ // try auto-correction
+ //if (autocorrect_ && hasPrevAtom() && math_autocorrect(prevAtom(), c))
+ // return true;
// no special circumstances, so insert the character without any fuss
- insert(c, lastcode_);
- lastcode_ = LM_TC_MIN;
+ insert(c);
+ autocorrect_ = true;
return true;
}
+void MathCursor::setSelection(MathIterator const & where, size_type n)
+{
+ selection_ = true;
+ Anchor_ = where;
+ Cursor_ = where;
+ cursor().pos_ += n;
+}
+
+
+void MathCursor::insetToggle()
+{
+ if (hasNextAtom()) {
+ // toggle previous inset ...
+ nextAtom().nucleus()->lock(!nextAtom()->lock());
+ } else if (popLeft() && hasNextAtom()) {
+ // ... or enclosing inset if we are in the last inset position
+ nextAtom().nucleus()->lock(!nextAtom()->lock());
+ posRight();
+ }
+}
+
+
+string MathCursor::info() const
+{
+ ostringstream os;
+ os << "Math editor mode. ";
+ for (int i = 0, n = depth(); i < n; ++i) {
+ Cursor_[i].par_->infoize(os);
+ os << " ";
+ }
+ if (hasPrevAtom())
+ if (prevAtom()->asSymbolInset() || prevAtom()->asScriptInset())
+ prevAtom()->infoize(os);
+ os << " ";
+ return os.str().c_str(); // .c_str() needed for lyxstring
+}
+
+
+unsigned MathCursor::depth() const
+{
+ return Cursor_.size();
+}
+
+
+
+
+namespace {
+
+void region(MathCursorPos const & i1, MathCursorPos const & i2,
+ MathInset::row_type & r1, MathInset::row_type & r2,
+ MathInset::col_type & c1, MathInset::col_type & c2)
+{
+ MathInset * p = i1.par_;
+ c1 = p->col(i1.idx_);
+ c2 = p->col(i2.idx_);
+ if (c1 > c2)
+ swap(c1, c2);
+ r1 = p->row(i1.idx_);
+ r2 = p->row(i2.idx_);
+ if (r1 > r2)
+ swap(r1, r2);
+}
+
+}
+
+
+MathGridInset MathCursor::grabSelection() const
+{
+ if (!selection_)
+ return MathGridInset();
+ MathCursorPos i1;
+ MathCursorPos i2;
+ getSelection(i1, i2);
+ // shouldn't we assert on i1.par_ == i2.par_?
+ if (i1.idx_ == i2.idx_) {
+ MathGridInset data(1, 1);
+ MathArray::const_iterator it = i1.cell().begin();
+ data.cell(0) = MathArray(it + i1.pos_, it + i2.pos_);
+ return data;
+ }
+ row_type r1, r2;
+ col_type c1, c2;
+ region(i1, i2, r1, r2, c1, c2);
+ MathGridInset data(c2 - c1 + 1, r2 - r1 + 1);
+ 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);
+ }
+ return data;
+}
+
+
+void MathCursor::eraseSelection()
+{
+ MathCursorPos i1;
+ MathCursorPos i2;
+ 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)
+ for (col_type col = c1; col <= c2; ++col)
+ p->cell(p->index(row, col)).clear();
+ }
+ cursor() = i1;
+}
+
+
+MathGridInset MathCursor::grabAndEraseSelection()
+{
+ if (!selection_)
+ return MathGridInset();
+ MathGridInset res = grabSelection();
+ eraseSelection();
+ selection_ = false;
+ return res;
+}
+
MathCursorPos MathCursor::normalAnchor() const
{
- if (Anchor_.size() < Cursor_.size()) {
+ if (Anchor_.size() < depth()) {
Anchor_ = Cursor_;
lyxerr << "unusual Anchor size\n";
- dump("1");
}
- //lyx::Assert(Anchor_.size() >= Cursor_.size());
+ //lyx::Assert(Anchor_.size() >= cursor.depth());
// use Anchor on the same level as Cursor
- MathCursorPos normal = Anchor_[Cursor_.size() - 1];
- if (Cursor_.size() < Anchor_.size() && !(normal < cursor())) {
+ MathCursorPos normal = Anchor_[depth() - 1];
+ if (depth() < Anchor_.size() && !(normal < cursor())) {
// anchor is behind cursor -> move anchor behind the inset
++normal.pos_;
}
}
-void MathCursor::stripFromLastEqualSign()
+MathInset::result_type MathCursor::dispatch(FuncRequest const & cmd)
{
- // find position of last '=' in the array
- MathArray & ar = cursor().cell();
- MathArray::const_iterator et = ar.end();
- for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
- if ((*it)->getChar() == '=')
- et = it;
+ // try to dispatch to adajcent items if they are not editable
+ // actually, this should only happen for mouse clicks...
+ idx_type d1;
+ pos_type d2;
+ if (hasNextAtom() && !openable(nextAtom(), false)) {
+ MathInset::result_type res = nextAtom().nucleus()->dispatch(cmd, d1, d2);
+ if (res != MathInset::UNDISPATCHED)
+ return res;
+ }
+ if (hasPrevAtom() && !openable(prevAtom(), false)) {
+ MathInset::result_type res = prevAtom().nucleus()->dispatch(cmd, d1, d2);
+ if (res != MathInset::UNDISPATCHED)
+ return res;
+ }
+
+ for (int i = Cursor_.size() - 1; i >= 0; --i) {
+ MathCursorPos & pos = Cursor_[i];
+ MathInset::result_type const res
+ = pos.par_->dispatch(cmd, pos.idx_, pos.pos_);
+ if (res != MathInset::UNDISPATCHED) {
+ if (res == MathInset::DISPATCHED_POP) {
+ Cursor_.shrink(i + 1);
+ selClear();
+ }
+ return res;
+ }
+ }
+ return MathInset::UNDISPATCHED;
+}
+
- // delete everything behind this position
- ar.erase(et - ar.begin(), ar.size());
- pos() = ar.size();
+MathInset::mode_type MathCursor::currentMode() const
+{
+ for (int i = Cursor_.size() - 1; i >= 0; --i) {
+ MathInset::mode_type res = Cursor_[i].par_->currentMode();
+ if (res != MathInset::UNDECIDED_MODE)
+ return res;
+ }
+ return MathInset::UNDECIDED_MODE;
}
+void releaseMathCursor(BufferView * bv)
+{
+ if (!mathcursor)
+ return;
+ mathcursor->formula()->hideInsetCursor(bv);
+ delete mathcursor;
+ mathcursor = 0;
+}