-/*
- * File: math_cursor.C
- * Purpose: Interaction for mathed
- * Author: Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
- * Created: January 1996
- * Description: Math interaction for a WYSIWYG math editor.
+/**
+ * \file math_cursor.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
*
- * Dependencies: Xlib, XForms
+ * \author Alejandro Aguilar Sierra
+ * \author André Pönitz
*
- * Copyright: 1996, Alejandro Aguilar Sierra
- *
- * Version: 0.8beta, Math & Lyx project.
- *
- * You are free to use and modify this code under the terms of
- * the GNU General Public Licence version 2 or later.
+ * Full author contact details are available in file CREDITS.
*/
#include <config.h>
-#include <lyxrc.h>
-
-#ifdef __GNUG__
-#pragma implementation
-#endif
-#include "support/lstrings.h"
-#include "support/LAssert.h"
-#include "BufferView.h"
-#include "debug.h"
-#include "LColor.h"
-#include "frontends/Painter.h"
#include "math_cursor.h"
+#include "lyxrc.h"
+#include "support/limited_stack.h"
+#include "dispatchresult.h"
+#include "debug.h"
+#include "support/std_sstream.h"
#include "formulabase.h"
-#include "math_autocorrect.h"
-#include "math_arrayinset.h"
+#include "funcrequest.h"
#include "math_braceinset.h"
-#include "math_casesinset.h"
+#include "math_commentinset.h"
#include "math_charinset.h"
-#include "math_extern.h"
#include "math_factory.h"
-#include "math_hullinset.h"
-#include "math_iterator.h"
+#include "math_gridinset.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_support.h"
#include "math_unknowninset.h"
-#include <algorithm>
-#include <cctype>
+#include <boost/assert.hpp>
//#define FILEDEBUG 1
+using std::string;
using std::endl;
+#ifndef CXX_GLOBAL_CSTD
+using std::isalpha;
+#endif
using std::min;
-using std::max;
using std::swap;
-using std::vector;
+
using std::ostringstream;
-using std::isalpha;
// matheds own cut buffer
-MathGridInset theCutBuffer = MathGridInset(1, 1);
+limited_stack<string> theCutBuffer;
MathCursor::MathCursor(InsetFormulaBase * formula, bool front)
- : formula_(formula), autocorrect_(false), selection_(false)
+ : formula_(formula), autocorrect_(false), selection_(false), targetx_(-1)
{
front ? first() : last();
Anchor_ = Cursor_;
MathCursor::~MathCursor()
{
- // ensure that 'notifyCursorLeave' is called
- while (popLeft())
- ;
-}
+ // ensure that 'notifyCursorLeave' is called
+ while (popLeft())
+ ;
+}
void MathCursor::push(MathAtom & t)
{
- Cursor_.push_back(MathCursorPos(t.nucleus()));
+ Cursor_.push_back(CursorPos(t.nucleus()));
}
void MathCursor::pushLeft(MathAtom & t)
{
- //cerr << "Entering atom "; t->write(cerr, false); cerr << " left\n";
+ //lyxerr << "Entering atom " << t << " left" << endl;
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" << endl;
posLeft();
push(t);
t->idxLast(idx(), pos());
bool MathCursor::popLeft()
{
- //cerr << "Leaving atom to the left\n";
+ //lyxerr << "Leaving atom to the left" << endl;
if (depth() <= 1) {
if (depth() == 1)
- par()->notifyCursorLeaves();
+ inset()->notifyCursorLeaves(idx());
return false;
}
- par()->notifyCursorLeaves();
+ inset()->notifyCursorLeaves(idx());
Cursor_.pop_back();
return true;
}
bool MathCursor::popRight()
{
- //cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n";
+ //lyxerr << "Leaving atom "; inset()->write(cerr, false); cerr << " right" << endl;
if (depth() <= 1) {
if (depth() == 1)
- par()->notifyCursorLeaves();
+ inset()->notifyCursorLeaves(idx());
return false;
}
- par()->notifyCursorLeaves();
+ inset()->notifyCursorLeaves(idx());
Cursor_.pop_back();
posRight();
return true;
#if FILEDEBUG
void MathCursor::dump(char const * what) const
{
- lyxerr << "MC: " << what << "\n";
- lyxerr << " Cursor: " << depth() << "\n";
+ lyxerr << "MC: " << what << endl;
+ lyxerr << " Cursor: " << depth() << endl;
for (unsigned i = 0; i < depth(); ++i)
- lyxerr << " i: " << i << " " << Cursor_[i] << "\n";
- lyxerr << " Anchor: " << Anchor_.size() << "\n";
+ lyxerr << " i: " << i << ' ' << Cursor_[i] << endl;
+ lyxerr << " Anchor: " << Anchor_.size() << endl;
for (unsigned i = 0; i < Anchor_.size(); ++i)
- lyxerr << " i: " << i << " " << Anchor_[i] << "\n";
- lyxerr << " sel: " << selection_ << "\n";
+ lyxerr << " i: " << i << ' ' << Anchor_[i] << endl;
+ lyxerr << " sel: " << selection_ << endl;
}
#else
void MathCursor::dump(char const *) const {}
bool MathCursor::isInside(MathInset const * p) const
{
for (unsigned i = 0; i < depth(); ++i)
- if (Cursor_[i].par_ == p)
+ if (Cursor_[i].inset_ == p)
return true;
return false;
}
if (t->lock())
return false;
- if (t->asScriptInset())
- return false;
-
- if (!sel) {
+ if (sel) {
// we can't move into anything new during selection
if (depth() == Anchor_.size())
return false;
- if (t.nucleus() != Anchor_[depth()].par_)
+ if (t.operator->() != Anchor_[depth()].inset_)
return false;
}
return true;
}
+bool MathCursor::inNucleus() const
+{
+ return inset()->asScriptInset() && idx() == 2;
+}
+
+
bool MathCursor::posLeft()
{
if (pos() == 0)
{
Cursor_.clear();
push(formula_->par());
- par()->idxFirst(idx(), pos());
+ inset()->idxFirst(idx(), pos());
}
{
Cursor_.clear();
push(formula_->par());
- par()->idxLast(idx(), pos());
+ inset()->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)
- if (cursor[i].par_ != anchor[i].par_)
+ for (MathIterator::size_type i = 0; i < cursor.size(); ++i)
+ if (cursor[i].inset_ != anchor[i].inset_)
return false;
// position should be ok.
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");
}
autocorrect_ = false;
selHandle(sel);
macroModeClose();
- if (!par()->idxHome(idx(), pos()))
+ if (!inset()->idxHome(idx(), pos()))
return popLeft();
dump("home 2");
+ targetx_ = -1; // "no target"
return true;
}
autocorrect_ = false;
selHandle(sel);
macroModeClose();
- if (!par()->idxEnd(idx(), pos()))
+ if (!inset()->idxEnd(idx(), pos()))
return popRight();
dump("end 2");
+ targetx_ = -1; // "no target"
return true;
}
void MathCursor::markInsert()
{
- //lyxerr << "inserting mark\n";
+ //lyxerr << "inserting mark" << endl;
array().insert(pos(), MathAtom(new MathCharInset(0)));
}
void MathCursor::markErase()
{
- //lyxerr << "deleting mark\n";
+ //lyxerr << "deleting mark" << endl;
array().erase(pos());
}
}
+void MathCursor::insert2(string const & str)
+{
+ MathArray ar;
+ asArray(str, ar);
+ insert(ar);
+}
+
+
void MathCursor::insert(string const & str)
{
- //lyxerr << "inserting '" << str << "'\n";
+ //lyxerr << "inserting '" << str << "'" << endl;
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";
+ //lyxerr << "inserting '" << c << "'" << endl;
selClearOrDel();
plainInsert(MathAtom(new MathCharInset(c)));
}
}
+void MathCursor::niceInsert(string const & t)
+{
+ MathArray ar;
+ asArray(t, ar);
+ if (ar.size() == 1)
+ niceInsert(ar[0]);
+ else
+ insert(ar);
+}
+
+
void MathCursor::niceInsert(MathAtom const & t)
{
macroModeClose();
- MathGridInset safe = grabAndEraseSelection();
+ string safe = grabAndEraseSelection();
plainInsert(t);
// enter the new inset and move the contents of the selection if possible
if (t->isActive()) {
macroModeClose();
if (selection_)
eraseSelection();
-
array().insert(pos(), ar);
pos() += ar.size();
}
-void MathCursor::paste(MathArray const & ar)
+void MathCursor::paste(string const & data)
{
- Anchor_ = Cursor_;
- selection_ = true;
- array().insert(pos(), ar);
- pos() += ar.size();
+ dispatch(FuncRequest(LFUN_PASTE, data));
}
-void MathCursor::paste(MathGridInset const & data)
+bool MathCursor::backspace()
{
- if (data.nargs() == 1) {
- // single cell/part of cell
- paste(data.cell(0));
- } else {
- // mulitple cells
- idx_type idx; // index of upper left cell
- MathGridInset * p = 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)));
- }
- // append the left over horizontal cells to the last column
- idx_type i = p->index(row + p->row(idx), p->ncols() - 1);
- for (MathInset::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)));
+ autocorrect_ = false;
+
+ if (selection_) {
+ selDel();
+ return true;
}
-}
-void MathCursor::backspace()
-{
- autocorrect_ = false;
if (pos() == 0) {
+ if (inset()->ncols() == 1 &&
+ inset()->nrows() == 1 &&
+ depth() == 1 &&
+ size() == 0)
+ return false;
pullArg();
- return;
+ return true;
}
- if (selection_) {
- selDel();
- return;
+ if (inMacroMode()) {
+ MathUnknownInset * p = activeMacro();
+ if (p->name().size() > 1) {
+ p->setName(p->name().substr(0, p->name().size() - 1));
+ return true;
+ }
}
- MathScriptInset * p = prevAtom()->asScriptInset();
- if (p) {
- p->removeScript(p->hasUp());
- // Don't delete if there is anything left
- if (p->hasUp() || p->hasDown())
- return;
+ if (hasPrevAtom() && prevAtom()->nargs() > 0) {
+ // let's require two backspaces for 'big stuff' and
+ // highlight on the first
+ left(true);
+ } else {
+ --pos();
+ plainErase();
}
-
- --pos();
- plainErase();
+ return true;
}
-void MathCursor::erase()
+bool MathCursor::erase()
{
autocorrect_ = false;
if (inMacroMode())
- return;
+ return true;
if (selection_) {
selDel();
- return;
+ return true;
}
// delete empty cells if possible
if (array().empty())
- if (par()->idxDelete(idx()))
- return;
+ if (inset()->idxDelete(idx()))
+ return true;
// old behaviour when in last position of cell
if (pos() == size()) {
- par()->idxGlue(idx());
- return;
- }
-
- MathScriptInset * p = nextAtom()->asScriptInset();
- if (p) {
- p->removeScript(p->hasUp());
- // Don't delete if there is anything left
- if (p->hasUp() || p->hasDown())
- return;
+ if (inset()->ncols() == 1 && inset()->nrows() == 1 && depth() == 1 && size() == 0)
+ return false;
+ else{
+ inset()->idxGlue(idx());
+ return true;
+ }
}
plainErase();
-}
-
-
-void MathCursor::delLine()
-{
- autocorrect_ = false;
- macroModeClose();
-
- if (selection_) {
- selDel();
- return;
- }
-
- if (par()->nrows() > 1) {
- // grid are the only things with more than one row...
- lyx::Assert(par()->asGridInset());
- par()->asGridInset()->delRow(hullRow());
- }
-
- if (idx() >= par()->nargs())
- idx() = par()->nargs() - 1;
-
- if (pos() > size())
- pos() = size();
+ return true;
}
dump("up 1");
macroModeClose();
selHandle(sel);
- cursor_type save = Cursor_;
+ MathIterator save = Cursor_;
if (goUpDown(true))
return true;
Cursor_ = save;
dump("down 1");
macroModeClose();
selHandle(sel);
- cursor_type save = Cursor_;
+ MathIterator save = Cursor_;
if (goUpDown(false))
return true;
Cursor_ = save;
}
-bool MathCursor::toggleLimits()
-{
- if (!hasNextAtom())
- return false;
- MathScriptInset * t = nextAtom()->asScriptInset();
- if (!t)
- return false;
- int old = t->limits();
- t->limits(old < 0 ? 1 : -1);
- return old != t->limits();
-}
-
-
void MathCursor::macroModeClose()
{
- MathUnknownInset * p = inMacroMode();
- if (!p)
+ if (!inMacroMode())
return;
+ MathUnknownInset * p = activeMacro();
p->finalize();
string s = p->name();
--pos();
array().erase(pos());
- if (s != "\\")
- interpret(s);
+
+ // do nothing if the macro name is empty
+ if (s == "\\")
+ return;
+
+ string const name = s.substr(1);
+
+ // prevent entering of recursive macros
+ if (formula()->lyxCode() == InsetOld::MATHMACRO_CODE
+ && formula()->getInsetName() == name)
+ lyxerr << "can't enter recursive macro" << endl;
+
+ niceInsert(createMathInset(name));
}
string MathCursor::macroName() const
{
- return inMacroMode() ? inMacroMode()->name() : string();
+ return inMacroMode() ? activeMacro()->name() : string();
}
void MathCursor::selClear()
{
+ Anchor_.clear();
selection_ = false;
}
{
dump("selCopy");
if (selection_) {
- theCutBuffer = grabSelection();
+ theCutBuffer.push(grabSelection());
selection_ = false;
} else {
- theCutBuffer = MathGridInset(1, 1);
+ //theCutBuffer.erase();
}
}
void MathCursor::selCut()
{
dump("selCut");
- theCutBuffer = grabAndEraseSelection();
+ theCutBuffer.push(grabAndEraseSelection());
}
}
-void MathCursor::selPaste()
+void MathCursor::selPaste(size_t n)
{
dump("selPaste");
selClearOrDel();
- paste(theCutBuffer);
+ if (n < theCutBuffer.size())
+ paste(theCutBuffer[n]);
//grabSelection();
selection_ = false;
}
}
-void MathCursor::selGet(MathArray & ar)
-{
- dump("selGet");
- if (selection_)
- ar = grabSelection().glue();
-}
-
-
-
-void MathCursor::drawSelection(MathPainterInfo & pain) const
+void MathCursor::drawSelection(PainterInfo & pi) const
{
if (!selection_)
return;
-
- MathCursorPos i1;
- MathCursorPos i2;
+ CursorPos i1;
+ CursorPos 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.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
- } else {
- 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.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
+ i1.inset_->drawSelection(pi, i1.idx_, i1.pos_, i2.idx_, i2.pos_);
}
-void MathCursor::handleNest(MathAtom const & at)
+void MathCursor::handleNest(MathAtom const & a, int c)
{
- at->cell(0) = grabAndEraseSelection().glue();
+ MathAtom at = a;
+ asArray(grabAndEraseSelection(), at.nucleus()->cell(c));
insert(at);
pushRight(prevAtom());
}
-void MathCursor::getPos(int & x, int & y)
+void MathCursor::getPos(int & x, int & y) const
+{
+ inset()->getPos(idx(), pos(), x, y);
+}
+
+
+int MathCursor::targetX() const
{
- par()->getPos(idx(), pos(), x, y);
+ if (targetx_ != -1)
+ return targetx_;
+ int x = 0, y = 0;
+ getPos(x, y);
+ return x;
}
-MathInset * MathCursor::par() const
+MathInset * MathCursor::inset() const
{
- return cursor().par_;
+ return cursor().inset_;
}
}
+void MathCursor::adjust(pos_type from, difference_type diff)
+{
+ if (cursor().pos_ > from)
+ cursor().pos_ += diff;
+ if (Anchor_.back().pos_ > from)
+ Anchor_.back().pos_ += diff;
+ // just to be on the safe side
+ // theoretically unecessary
+ normalize();
+}
+
+
MathCursor::pos_type & MathCursor::pos()
{
return cursor().pos_;
}
-MathUnknownInset * MathCursor::inMacroMode() const
+bool MathCursor::inMacroMode() const
{
if (!hasPrevAtom())
- return 0;
- MathUnknownInset * p = prevAtom()->asUnknownInset();
- return (p && !p->final()) ? p : 0;
+ 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;
}
MathGridInset * MathCursor::enclosingGrid(MathCursor::idx_type & idx) const
{
for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
- MathGridInset * p = Cursor_[i].par_->asGridInset();
+ MathGridInset * p = Cursor_[i].inset_->asGridInset();
if (p) {
idx = Cursor_[i].idx_;
return p;
}
-MathHullInset * MathCursor::enclosingHull(MathCursor::idx_type & idx) const
+void MathCursor::popToHere(MathInset const * p)
{
- for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
- MathHullInset * p = Cursor_[i].par_->asHullInset();
- if (p) {
- idx = Cursor_[i].idx_;
- return p;
- }
- }
- return 0;
+ while (depth() && Cursor_.back().inset_ != p)
+ Cursor_.pop_back();
}
void MathCursor::popToEnclosingGrid()
{
- while (depth() && !Cursor_.back().par_->asGridInset())
+ while (depth() && !Cursor_.back().inset_->asGridInset())
Cursor_.pop_back();
}
void MathCursor::popToEnclosingHull()
{
- while (depth() && !Cursor_.back().par_->asHullInset())
+ while (depth() && !Cursor_.back().inset_->asHullInset())
Cursor_.pop_back();
}
{
dump("pullarg");
MathArray a = array();
-
- 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;
- }
-
if (popLeft()) {
plainErase();
array().insert(pos(), a);
void MathCursor::touch()
{
- cursor_type::const_iterator it = Cursor_.begin();
- cursor_type::const_iterator et = Cursor_.end();
+ MathIterator::const_iterator it = Cursor_.begin();
+ MathIterator::const_iterator et = Cursor_.end();
for ( ; it != et; ++it)
- it->xcell().touch();
+ it->cell().touch();
}
void MathCursor::normalize()
{
- if (idx() >= par()->nargs()) {
+ if (idx() >= inset()->nargs()) {
lyxerr << "this should not really happen - 1: "
- << idx() << " " << par()->nargs() << "\n";
+ << idx() << ' ' << inset()->nargs()
+ << " in: " << inset() << endl;
dump("error 2");
}
- idx() = min(idx(), par()->nargs() - 1);
+ idx() = min(idx(), inset()->nargs() - 1);
if (pos() > size()) {
lyxerr << "this should not really happen - 2: "
- << pos() << " " << size() << " in idx: " << idx()
- << " in atom: '";
+ << pos() << ' ' << size() << " in idx: " << idx()
+ << " in atom: '";
WriteStream wi(lyxerr, false, true);
- par()->write(wi);
- lyxerr << "\n";
+ inset()->write(wi);
+ lyxerr << endl;
dump("error 4");
}
pos() = min(pos(), size());
-
- // remove empty scripts if possible
- if (1) {
- for (pos_type i = 0; i < size(); ++i) {
- MathScriptInset * p = array()[i]->asScriptInset();
- if (p) {
- p->removeEmptyScripts();
- //if (p->empty())
- // array().erase(i);
- }
- }
- }
-
- // fix again position
- pos() = min(pos(), size());
}
}
-MathCursor::col_type MathCursor::hullCol() const
-{
- idx_type idx = 0;
- MathHullInset * p = enclosingHull(idx);
- return p->col(idx);
-}
-
-
-MathCursor::row_type MathCursor::hullRow() const
-{
- idx_type idx = 0;
- MathHullInset * p = enclosingHull(idx);
- return p->row(idx);
-}
-
-
bool MathCursor::hasPrevAtom() const
{
return pos() > 0;
MathAtom const & MathCursor::prevAtom() const
{
- lyx::Assert(pos() > 0);
+ BOOST_ASSERT(pos() > 0);
return array()[pos() - 1];
}
MathAtom & MathCursor::prevAtom()
{
- lyx::Assert(pos() > 0);
+ BOOST_ASSERT(pos() > 0);
return array()[pos() - 1];
}
MathAtom const & MathCursor::nextAtom() const
{
- lyx::Assert(pos() < size());
+ BOOST_ASSERT(pos() < size());
return array()[pos()];
}
MathAtom & MathCursor::nextAtom()
{
- lyx::Assert(pos() < size());
+ BOOST_ASSERT(pos() < size());
return array()[pos()];
}
{
static MathArray dummy;
- if (idx() >= par()->nargs()) {
- lyxerr << "############ idx_ " << idx() << " not valid\n";
+ if (idx() >= inset()->nargs()) {
+ lyxerr << "############ idx_ " << idx() << " not valid" << endl;
return dummy;
}
if (depth() == 0) {
- lyxerr << "############ depth() == 0 not valid\n";
+ lyxerr << "############ depth() == 0 not valid" << endl;
return dummy;
}
}
-MathXArray & MathCursor::xarray() const
-{
- static MathXArray dummy;
-
- if (depth() == 0) {
- lyxerr << "############ depth() == 0 not valid\n";
- return dummy;
- }
-
- return cursor().xcell();
-}
-
-
void MathCursor::idxNext()
{
- par()->idxNext(idx(), pos());
+ inset()->idxNext(idx(), pos());
}
void MathCursor::idxPrev()
{
- par()->idxPrev(idx(), pos());
+ inset()->idxPrev(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())
- ;
-
- idx_type dummy;
- MathHullInset * p = enclosingHull(dummy);
- if (!p)
- return;
-
- if (p->getType() == "simple" || p->getType() == "equation") {
- p->mutate("eqnarray");
- idx() = 1;
- pos() = 0;
- } 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;
}
-void MathCursor::getSelection(MathCursorPos & i1, MathCursorPos & i2) const
+void MathCursor::getSelection(CursorPos & i1, CursorPos & i2) const
{
- MathCursorPos anc = normalAnchor();
+ CursorPos anc = normalAnchor();
if (anc < cursor()) {
i1 = anc;
i2 = cursor();
}
-MathCursorPos & MathCursor::cursor()
+CursorPos & MathCursor::cursor()
{
- lyx::Assert(depth());
+ BOOST_ASSERT(depth());
return Cursor_.back();
}
-MathCursorPos const & MathCursor::cursor() const
+CursorPos const & MathCursor::cursor() const
{
- lyx::Assert(depth());
+ BOOST_ASSERT(depth());
return Cursor_.back();
}
// 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;
+ int xo = 0;
+ int yo = 0;
getPos(xo, yo);
// check if we had something else in mind, if not, this is the future goal
xo = targetx_;
// 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;
+ if (!selection()) {
+ // 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" << endl;
+ 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 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" << endl;
+ return true;
+ }
}
}
- // try current cell
+ // try current cell for e.g. text insets
+ if (inset()->idxUpDown2(idx(), pos(), up, targetx_))
+ return true;
+
//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";
+ // lyxerr << "updown: handled by brute find in the same cell" << endl;
// return true;
//}
// try to find an inset that knows better then we
while (1) {
- ///lyxerr << "updown: We are in " << *par() << " idx: " << idx() << '\n';
+ //lyxerr << "updown: We are in " << inset() << " idx: " << idx() << endl;
// 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";
+ if (inset()->idxUpDown(idx(), pos(), up, targetx_)) {
+ // try to find best position within this inset
+ if (!selection())
+ bruteFind2(xo, yo);
return true;
}
- // leave inset
- if (!popLeft()) {
- // no such inset found, just take something "above"
- ///lyxerr << "updown: handled by strange case\n";
+ // no such inset found, just take something "above"
+ //lyxerr << "updown: handled by strange case" << endl;
+ 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;
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());
while (1) {
// avoid invalid nesting when selecting
- if (!selection_ || positionable(it.cursor(), Anchor_)) {
- MathCursorPos const & top = it.position();
- int xo = top.xpos();
- int yo = top.ypos();
+ 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);
+ //lyxerr << "x: " << x << " y: " << y << " d: " << endl;
// '<=' 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();
+ best_cursor = it;
}
}
}
}
-bool MathCursor::idxLineFirst()
+void MathCursor::bruteFind2(int x, int y)
{
- idx() -= idx() % par()->ncols();
- pos() = 0;
- return true;
+ double best_dist = 1e10;
+
+ MathIterator it = Cursor_;
+ it.back().setPos(0);
+ MathIterator et = Cursor_;
+ et.back().setPos(it.cell().size());
+ for (int i = 0; ; ++i) {
+ int xo, yo;
+ it.back().getPos(xo, yo);
+ 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'
+ lyxerr << "i: " << i << " d: " << d << " best: " << best_dist << endl;
+ if (d <= best_dist) {
+ best_dist = d;
+ Cursor_ = it;
+ }
+ if (it == et)
+ break;
+ ++it;
+ }
}
bool MathCursor::idxLineLast()
{
- idx() -= idx() % par()->ncols();
- idx() += par()->ncols() - 1;
+ idx() -= idx() % inset()->ncols();
+ idx() += inset()->ncols() - 1;
pos() = size();
return true;
}
bool MathCursor::idxLeft()
{
- return par()->idxLeft(idx(), pos());
+ return inset()->idxLeft(idx(), pos());
}
bool MathCursor::idxRight()
{
- return par()->idxRight(idx(), pos());
-}
-
-
-bool MathCursor::interpret(string const & s)
-{
- //lyxerr << "interpret 1: '" << s << "'\n";
- if (s.empty())
- return true;
-
- //lyxerr << "char: '" << s[0] << "' int: " << int(s[0]) << endl;
- //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 = 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 v_align;
- string h_align;
- istringstream is(s.substr(6).c_str());
- is >> m >> n >> v_align >> h_align;
- m = max(1u, m);
- n = max(1u, n);
- v_align += 'c';
- niceInsert(MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
- return true;
- }
-
- if (s.size() >= 7 && s.substr(0, 7) == "replace") {
- ReplaceData rep;
- istringstream is(s.substr(7).c_str());
- string from, to;
- is >> from >> to;
- mathed_parse_cell(rep.from, from);
- mathed_parse_cell(rep.to, to);
- lyxerr << "replacing '" << from << "' with '" << to << "'\n";
- par()->replace(rep);
- return true;
- }
-
- string name = s.substr(1);
-
- if (name == "over" || name == "choose" || name == "atop") {
- MathArray ar = array();
- MathAtom t(createMathInset(name));
- t->asNestInset()->cell(0).swap(array());
- pos() = 0;
- niceInsert(t);
- popRight();
- left();
- return true;
- }
-
- // 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(name));
- return true;
+ return inset()->idxRight(idx(), pos());
}
// Hack to get \\^ and \\_ working
if (inMacroMode() && macroName() == "\\") {
if (up)
- interpret("\\mathcircumflex");
+ niceInsert(createMathInset("mathcircumflex"));
else
interpret('_');
return true;
}
macroModeClose();
- MathGridInset safe = grabAndEraseSelection();
- if (hasPrevAtom() && prevAtom()->asScriptInset()) {
- prevAtom()->asScriptInset()->ensure(up);
+ string safe = grabAndEraseSelection();
+ if (inNucleus()) {
+ // we are in a nucleus of a script inset, move to _our_ script
+ inset()->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;
bool MathCursor::interpret(char c)
{
- //lyxerr << "interpret 2: '" << c << "'\n";
+ //lyxerr << "interpret 2: '" << c << "'" << endl;
targetx_ = -1; // "no target"
if (inMacroArgMode()) {
--pos();
plainErase();
int n = c - '0';
- MathMacroTemplate * p = formula()->par()->asMacroTemplate();
+ MathMacroTemplate const * p = formula()->par()->asMacroTemplate();
if (p && 1 <= n && n <= p->numargs())
insert(MathAtom(new MathMacroArgument(c - '0')));
else {
// handle macroMode
if (inMacroMode()) {
string name = macroName();
- //lyxerr << "interpret name: '" << name << "'\n";
-
- if (name.empty() && c == '\\') {
- backspace();
- interpret("\\backslash");
- return true;
- }
+ //lyxerr << "interpret name: '" << name << "'" << endl;
if (isalpha(c)) {
- inMacroMode()->name() += c;
+ activeMacro()->setName(activeMacro()->name() + c);
return true;
}
if (name == "\\") {
// remove the '\\'
backspace();
- if (c == '\\')
- interpret("\\backslash");
- else
- interpret(string("\\") + c);
+ if (c == '\\') {
+ if (currentMode() == MathInset::TEXT_MODE)
+ niceInsert(createMathInset("textbackslash"));
+ else
+ niceInsert(createMathInset("backslash"));
+ } else if (c == '{') {
+ niceInsert(MathAtom(new MathBraceInset));
+ } else {
+ niceInsert(createMathInset(string(1, c)));
+ }
return true;
}
// leave macro mode and try again if necessary
macroModeClose();
- if (c != ' ')
+ if (c == '{')
+ niceInsert(MathAtom(new MathBraceInset));
+ else if (c != ' ')
interpret(c);
return true;
}
selClearOrDel();
if (c == '\\') {
- //lyxerr << "starting with macro\n";
+ //lyxerr << "starting with macro" << endl;
insert(MathAtom(new MathUnknownInset("\\", false)));
return true;
}
+ if (c == '\n') {
+ if (currentMode() == MathInset::TEXT_MODE)
+ insert(c);
+ return true;
+ }
+
if (c == ' ') {
if (currentMode() == MathInset::TEXT_MODE) {
// insert spaces in text mode,
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 (c == '{' || c == '}', c)) {
- insert(c); // LM_TC_TEX;
- return true;
- }
-*/
-
- if (c == '{') {
- niceInsert(MathAtom(new MathBraceInset));
- return true;
- }
-
- if (c == '}') {
- return true;
- }
-
- if (c == '$') {
- insert(createMathInset("$"));
+ if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
+ niceInsert(createMathInset(string(1, c)));
return true;
}
if (c == '%') {
- insert(createMathInset("%"));
- return true;
- }
-
-/*
- if (isalpha(c) && lastcode_ == LM_TC_GREEK) {
- insert(c, LM_TC_VAR);
+ niceInsert(MathAtom(new MathCommentInset));
return true;
}
- if (isalpha(c) && lastcode_ == LM_TC_GREEK1) {
- insert(c, LM_TC_VAR);
- lastcode_ = LM_TC_VAR;
- return true;
- }
-
- if (c == '\\') {
- insert(c, LM_TC_TEX);
- //bv->owner()->message(_("TeX mode"));
- return true;
- }
-*/
-
// try auto-correction
//if (autocorrect_ && hasPrevAtom() && math_autocorrect(prevAtom(), c))
// return true;
}
-void MathCursor::setSelection(cursor_type const & where, size_type n)
+void MathCursor::setSelection(MathIterator const & where, size_type n)
{
selection_ = true;
Anchor_ = where;
void MathCursor::insetToggle()
{
if (hasNextAtom()) {
- // toggle next inset ...
- nextAtom()->lock(!nextAtom()->lock());
+ // toggle previous inset ...
+ nextAtom().nucleus()->lock(!nextAtom()->lock());
} else if (popLeft() && hasNextAtom()) {
// ... or enclosing inset if we are in the last inset position
- nextAtom()->lock(!nextAtom()->lock());
+ nextAtom().nucleus()->lock(!nextAtom()->lock());
posRight();
}
}
ostringstream os;
os << "Math editor mode. ";
for (int i = 0, n = depth(); i < n; ++i) {
- Cursor_[i].par_->infoize(os);
+ Cursor_[i].inset_->infoize(os);
os << " ";
}
if (hasPrevAtom())
- if (prevAtom()->asSymbolInset() || prevAtom()->asScriptInset())
- prevAtom()->infoize(os);
+ prevAtom()->infoize2(os);
os << " ";
- return os.str().c_str(); // .c_str() needed for lyxstring
+ return os.str();
}
namespace {
-void region(MathCursorPos const & i1, MathCursorPos const & i2,
+void region(CursorPos const & i1, CursorPos const & i2,
MathInset::row_type & r1, MathInset::row_type & r2,
MathInset::col_type & c1, MathInset::col_type & c2)
{
- MathInset * p = i1.par_;
+ MathInset * p = i1.inset_;
c1 = p->col(i1.idx_);
c2 = p->col(i2.idx_);
if (c1 > c2)
}
-MathGridInset MathCursor::grabSelection() const
+string MathCursor::grabSelection() const
{
if (!selection_)
- return MathGridInset();
- MathCursorPos i1;
- MathCursorPos i2;
+ return string();
+
+ CursorPos i1;
+ CursorPos i2;
getSelection(i1, i2);
- // shouldn't we assert on i1.par_ == i2.par_?
+
if (i1.idx_ == i2.idx_) {
- MathGridInset data(1, 1);
- data.cell(0) = MathArray(i1.cell(), i1.pos_, i2.pos_);
- return data;
+ MathArray::const_iterator it = i1.cell().begin();
+ return asString(MathArray(it + i1.pos_, it + i2.pos_));
}
+
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);
+
+ string data;
+ for (row_type row = r1; row <= r2; ++row) {
+ if (row > r1)
+ data += "\\\\";
+ for (col_type col = c1; col <= c2; ++col) {
+ if (col > c1)
+ data += '&';
+ data += asString(i1.inset_->cell(i1.inset_->index(row, col)));
}
+ }
return data;
}
void MathCursor::eraseSelection()
{
- MathCursorPos i1;
- MathCursorPos i2;
+ CursorPos i1;
+ CursorPos i2;
getSelection(i1, i2);
if (i1.idx_ == i2.idx_)
i1.cell().erase(i1.pos_, i2.pos_);
else {
- MathInset * p = i1.par_;
+ MathInset * p = i1.inset_;
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();
+ p->cell(p->index(row, col)).clear();
}
cursor() = i1;
}
-MathGridInset MathCursor::grabAndEraseSelection()
+string MathCursor::grabAndEraseSelection()
{
if (!selection_)
- return MathGridInset();
- MathGridInset res = grabSelection();
+ return string();
+ string res = grabSelection();
eraseSelection();
selection_ = false;
return res;
}
-MathCursorPos MathCursor::normalAnchor() const
+CursorPos MathCursor::normalAnchor() const
{
if (Anchor_.size() < depth()) {
Anchor_ = Cursor_;
- lyxerr << "unusual Anchor size\n";
+ lyxerr << "unusual Anchor size" << endl;
}
- //lyx::Assert(Anchor_.size() >= cursor.depth());
+ //lyx::BOOST_ASSERT(Anchor_.size() >= cursor.depth());
// use Anchor on the same level as Cursor
- MathCursorPos normal = Anchor_[depth() - 1];
+ CursorPos normal = Anchor_[depth() - 1];
if (depth() < Anchor_.size() && !(normal < cursor())) {
// anchor is behind cursor -> move anchor behind the inset
++normal.pos_;
}
-
-void MathCursor::handleExtern(const string & arg)
-{
- string lang;
- string extra;
- istringstream iss(arg.c_str());
- iss >> lang >> extra;
- if (extra.empty())
- extra = "noextra";
-
-
- if (selection()) {
- MathArray ar;
- selGet(ar);
- lyxerr << "use selection: " << ar << "\n";
- insert(pipeThroughExtern(lang, extra, ar));
- return;
- }
-
- MathArray eq;
- eq.push_back(MathAtom(new MathCharInset('=')));
-
- popToEnclosingHull();
-
- idx_type idx = 0;
- MathHullInset * hull = enclosingHull(idx);
- lyx::Assert(hull);
- idxLineFirst();
-
- if (hull->getType() == "simple") {
- MathArray::size_type pos = cursor().cell().find_last(eq);
- MathArray ar;
- if (pos == size()) {
- ar = array();
- lyxerr << "use whole cell: " << ar << "\n";
- } else {
- ar = MathArray(array(), pos + 1, size());
- lyxerr << "use partial cell form pos: " << pos << "\n";
+DispatchResult MathCursor::dispatch(FuncRequest const & cmd)
+{
+ // mouse clicks are somewhat special
+ // check
+ switch (cmd.action) {
+ case LFUN_MOUSE_PRESS:
+ case LFUN_MOUSE_MOTION:
+ case LFUN_MOUSE_RELEASE:
+ case LFUN_MOUSE_DOUBLE: {
+ CursorPos & pos = Cursor_.back();
+ int x = 0;
+ int y = 0;
+ getPos(x, y);
+ if (x < cmd.x && hasPrevAtom()) {
+ DispatchResult const res =
+ prevAtom().nucleus()->dispatch(cmd, pos.idx_, pos.pos_);
+ if (res.dispatched())
+ return res;
+ }
+ if (x > cmd.x && hasNextAtom()) {
+ DispatchResult const res =
+ nextAtom().nucleus()->dispatch(cmd, pos.idx_, pos.pos_);
+ if (res.dispatched())
+ return res;
+ }
}
- end();
- insert(eq);
- insert(pipeThroughExtern(lang, extra, ar));
- return;
- }
-
- if (hull->getType() == "equation") {
- lyxerr << "use equation inset\n";
- hull->mutate("eqnarray");
- MathArray & ar = cursor().cell();
- lyxerr << "use cell: " << ar << "\n";
- idxRight();
- cursor().cell() = eq;
- idxRight();
- cursor().cell() = pipeThroughExtern(lang, extra, ar);
- idxLineLast();
- return;
- }
-
- {
- lyxerr << "use eqnarray\n";
- idxLineLast();
- MathArray ar = cursor().cell();
- lyxerr << "use cell: " << ar << "\n";
- breakLine();
- idxRight();
- cursor().cell() = eq;
- idxRight();
- cursor().cell() = pipeThroughExtern(lang, extra, ar);
- idxLineLast();
+ default:
+ break;
}
-}
-
-
-int MathCursor::dispatch(string const & cmd)
-{
- // try to dispatch to adajcent items if they are not editable
- // actually, this should only happen for mouse clicks...
- if (hasNextAtom() && !openable(nextAtom(), false))
- if (int res = nextAtom()->dispatch(cmd, 0, 0))
- return res;
- if (hasPrevAtom() && !openable(prevAtom(), false))
- if (int res = prevAtom()->dispatch(cmd, 0, 0))
- return res;
-
for (int i = Cursor_.size() - 1; i >= 0; --i) {
- MathCursorPos & pos = Cursor_[i];
- if (int res = pos.par_->dispatch(cmd, pos.idx_, pos.pos_))
+ CursorPos & pos = Cursor_[i];
+ DispatchResult const res =
+ pos.inset_->dispatch(cmd, pos.idx_, pos.pos_);
+ if (res.dispatched()) {
+ if (res.val() == FINISHED) {
+ Cursor_.shrink(i + 1);
+ selClear();
+ }
return res;
+ }
}
- return 0;
+ return DispatchResult(false);
}
MathInset::mode_type MathCursor::currentMode() const
{
for (int i = Cursor_.size() - 1; i >= 0; --i) {
- MathInset::mode_type res = Cursor_[i].par_->currentMode();
+ MathInset::mode_type res = Cursor_[i].inset_->currentMode();
if (res != MathInset::UNDECIDED_MODE)
return res;
}
}
+void MathCursor::handleFont(string const & font)
+{
+ string safe;
+ if (selection()) {
+ macroModeClose();
+ safe = grabAndEraseSelection();
+ }
+
+ if (array().size()) {
+ // something left in the cell
+ if (pos() == 0) {
+ // cursor in first position
+ popLeft();
+ } else if (pos() == array().size()) {
+ // cursor in last position
+ popRight();
+ } else {
+ // cursor in between. split cell
+ MathArray::iterator bt = array().begin();
+ MathAtom at = createMathInset(font);
+ at.nucleus()->cell(0) = MathArray(bt, bt + pos());
+ cursor().cell().erase(bt, bt + pos());
+ popLeft();
+ plainInsert(at);
+ }
+ } else {
+ // nothing left in the cell
+ pullArg();
+ plainErase();
+ }
+ insert(safe);
+}
+
+
void releaseMathCursor(BufferView * bv)
{
- if (!mathcursor)
- return;
- mathcursor->formula()->hideInsetCursor(bv);
- delete mathcursor;
- mathcursor = 0;
+ if (mathcursor) {
+ InsetFormulaBase * f = mathcursor->formula();
+ delete mathcursor;
+ mathcursor = 0;
+ f->insetUnlock(bv);
+ }
}