#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 "formulabase.h"
#include "funcrequest.h"
#include "math_autocorrect.h"
-#include "math_arrayinset.h"
#include "math_braceinset.h"
#include "math_commentinset.h"
#include "math_charinset.h"
#include "math_extern.h"
#include "math_factory.h"
-#include "math_hullinset.h"
+#include "math_fontinset.h"
+#include "math_gridinset.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_support.h"
// matheds own cut buffer
-MathGridInset theCutBuffer = MathGridInset(1, 1);
+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())
+ ;
}
//cerr << "Leaving atom to the left\n";
if (depth() <= 1) {
if (depth() == 1)
- par()->notifyCursorLeaves();
+ par()->notifyCursorLeaves(idx());
return false;
}
- par()->notifyCursorLeaves();
+ par()->notifyCursorLeaves(idx());
Cursor_.pop_back();
return true;
}
//cerr << "Leaving atom "; par()->write(cerr, false); cerr << " right\n";
if (depth() <= 1) {
if (depth() == 1)
- par()->notifyCursorLeaves();
+ par()->notifyCursorLeaves(idx());
return false;
}
- par()->notifyCursorLeaves();
+ par()->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 positionable(MathIterator const & cursor, MathIterator const & anchor)
+bool positionable
+ (MathIterator const & cursor, MathIterator const & anchor)
{
// avoid deeper nested insets when selecting
if (cursor.size() > anchor.size())
}
+void MathCursor::niceInsert(string const & t)
+{
+ MathArray ar = asArray(t);
+ 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()) {
}
-void MathCursor::paste(MathGridInset const & data)
+void MathCursor::paste(string const & data)
{
- ostringstream os;
- WriteStream wi(os, false, false);
- data.write(wi);
- dispatch(FuncRequest(LFUN_PASTE, os.str()));
+ dispatch(FuncRequest(LFUN_PASTE, data));
}
-void MathCursor::backspace()
+bool MathCursor::backspace()
{
autocorrect_ = false;
- if (pos() == 0) {
- pullArg();
- return;
- }
if (selection_) {
selDel();
- return;
+ return true;
+ }
+
+ if (pos() == 0) {
+ if (par()->ncols() == 1 && par()->nrows() == 1 && depth() == 1 && size() == 0)
+ return false;
+ else{
+ pullArg();
+ return true;
+ }
}
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) {
+ return true;
}
}
-*/
--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;
+ return true;
// old behaviour when in last position of cell
if (pos() == size()) {
- par()->idxGlue(idx());
- return;
- }
-
-/*
- // 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();
+ if (par()->ncols() == 1 && par()->nrows() == 1 && depth() == 1 && size() == 0)
+ return false;
+ else{
+ par()->idxGlue(idx());
+ return true;
}
- return;
}
-*/
plainErase();
+ return true;
}
string s = p->name();
--pos();
array().erase(pos());
- if (s != "\\")
- interpret(s);
+
+ // do nothing if the macro name is empty
+ if (s == "\\")
+ return;
+
+ string name = s.substr(1);
+
+ // prevent entering of recursive macros
+ if (formula()->lyxCode() == Inset::MATHMACRO_CODE
+ && formula()->getInsetName() == name)
+ lyxerr << "can't enter recursive macro\n";
+
+ niceInsert(createMathInset(name));
}
theCutBuffer = grabSelection();
selection_ = false;
} else {
- theCutBuffer = MathGridInset(1, 1);
+ theCutBuffer.erase();
}
}
}
-void MathCursor::selGet(MathArray & ar)
-{
- dump("selGet");
- if (selection_)
- ar = grabSelection().glue();
-}
-
-
void MathCursor::drawSelection(MathPainterInfo & pi) const
{
if (!selection_)
void MathCursor::handleNest(MathAtom const & a)
{
MathAtom at = a;
- at.nucleus()->cell(0) = grabAndEraseSelection().glue();
+ at.nucleus()->cell(0) = asArray(grabAndEraseSelection());
insert(at);
pushRight(prevAtom());
}
}
+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_;
{
if (idx() >= par()->nargs()) {
lyxerr << "this should not really happen - 1: "
- << idx() << " " << par()->nargs() << " in: " << par() << "\n";
+ << idx() << ' ' << par()->nargs()
+ << " in: " << par() << endl;
dump("error 2");
}
idx() = min(idx(), par()->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";
+ 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].nucleus()->asScriptInset();
- if (p) {
- p->removeEmptyScripts();
- //if (p->empty())
- // array().erase(i);
- }
- }
- }
-
- // fix again position
- pos() = min(pos(), size());
}
while (1) {
///lyxerr << "updown: We are in " << *par() << " idx: " << idx() << '\n';
// ask inset first
- if (par()->idxUpDown(idx(), pos(), up, targetx_))
+ if (par()->idxUpDown(idx(), pos(), up, targetx_)) {
+ // try to find best position within this inset
+ if (!selection())
+ bruteFind2(xo, yo);
return true;
+ }
// no such inset found, just take something "above"
///lyxerr << "updown: handled by strange case\n";
}
+void MathCursor::bruteFind2(int x, int y)
+{
+ double best_dist = 1e10;
+
+ MathIterator it = Cursor_;
+ it.back().setPos(0);
+ MathIterator et = Cursor_;
+ et.back().setPos(it.cell().size());
+ while (1) {
+ 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'
+ if (d <= best_dist) {
+ best_dist = d;
+ Cursor_ = it;
+ }
+ if (it == et)
+ break;
+ ++it;
+ }
+}
+
+
bool MathCursor::idxLineLast()
{
idx() -= idx() % par()->ncols();
}
-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() >= 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") {
- MathAtom t(createMathInset(name));
- t.nucleus()->asNestInset()->cell(0) = array();
- array().clear();
- 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;
-}
-
-
bool MathCursor::script(bool up)
{
// Hack to get \\^ and \\_ working
}
macroModeClose();
- MathGridInset safe = grabAndEraseSelection();
+ string safe = grabAndEraseSelection();
if (inNucleus()) {
// we are in a nucleus of a script inset, move to _our_ script
par()->asScriptInset()->ensure(up);
niceInsert(createMathInset("textbackslash"));
else
niceInsert(createMathInset("backslash"));
- } else
+ } 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;
}
}
if (c == '\n') {
- if (currentMode() == MathInset::TEXT_MODE)
+ if (currentMode() == MathInset::TEXT_MODE)
insert(c);
return true;
}
}
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));
+ insert(c);
return true;
}
- if (c == '}') {
+ if (c == '{' || c == '}') {
+ niceInsert(createMathInset(string(1, c)));
return true;
}
return true;
}
-/*
- if (isalpha(c) && lastcode_ == LM_TC_GREEK) {
- insert(c, LM_TC_VAR);
- 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;
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 STRCONV(os.str());
}
}
-MathGridInset MathCursor::grabSelection() const
+string MathCursor::grabSelection() const
{
if (!selection_)
- return MathGridInset();
+ return string();
+
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;
+ 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.par_->cell(i1.par_->index(row, col)));
}
+ }
return data;
}
}
-MathGridInset MathCursor::grabAndEraseSelection()
+string MathCursor::grabAndEraseSelection()
{
if (!selection_)
- return MathGridInset();
- MathGridInset res = grabSelection();
+ return string();
+ string res = grabSelection();
eraseSelection();
selection_ = false;
return res;
MathInset::result_type MathCursor::dispatch(FuncRequest const & cmd)
{
- // 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_);
+ MathInset::result_type
+ res = pos.par_->dispatch(cmd, pos.idx_, pos.pos_);
if (res != MathInset::UNDISPATCHED) {
if (res == MathInset::DISPATCHED_POP) {
Cursor_.shrink(i + 1);
}
+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();
+ f->hideInsetCursor(bv);
+ delete mathcursor;
+ mathcursor = 0;
+ f->insetUnlock(bv);
+ }
}