+2001-10-10 André Pönitz <poenitz@gmx.net>
+
+ * math_cursor.C: introduce dummy "inner" position "between"
+ nucleus and scripts for smoother cursor movement
+
+ * math_cursor.C: use red dot to indicate empty nucleus
+
+
2001-10-02 André Pönitz <poenitz@gmx.net>
* math_cursor.C: leave red backslash as visual clue
2001-10-02 André Pönitz <poenitz@gmx.net>
* math_cursor.C: leave red backslash as visual clue
+void MathArray::push_back(MathAtom const & t)
+{
+ bf_.push_back(t);
+}
+
+
void MathArray::push_back(MathInset * p)
{
void MathArray::push_back(MathInset * p)
{
+ bf_.push_back(MathAtom(p));
return s;
for (MathTextCodes c = p->code(); it != end; ++it) {
return s;
for (MathTextCodes c = p->code(); it != end; ++it) {
+ if (!it->nucleus())
+ break;
p = it->nucleus()->asCharInset();
if (!p || it->up() || it->down() || p->code() != c)
break;
p = it->nucleus()->asCharInset();
if (!p || it->up() || it->down() || p->code() != c)
break;
void MathArray::write(ostream & os, bool fragile) const
{
for (const_iterator it = begin(); it != end(); ++it) {
void MathArray::write(ostream & os, bool fragile) const
{
for (const_iterator it = begin(); it != end(); ++it) {
- MathCharInset const * p = it->nucleus()->asCharInset();
- if (p && !it->up() && !it->down()) {
+ if (it->nucleus() && it->nucleus()->asCharInset()
+ && !it->up() && !it->down())
+ {
+ MathCharInset const * p = it->nucleus()->asCharInset();
// special handling for character sequences with the same code
string s = charSequence(it, end());
p->writeHeader(os);
// special handling for character sequences with the same code
string s = charSequence(it, end());
p->writeHeader(os);
///
void push_back(MathArray const &);
///
///
void push_back(MathArray const &);
///
+ void push_back(MathAtom const &);
+ ///
void pop_back();
///
MathAtom & back();
void pop_back();
///
MathAtom & back();
int MathAtom::dxx() const
{
int MathAtom::dxx() const
{
- lyx::Assert(nucleus());
- return hasLimits() ? (width() - nwid()) / 2 : 0;
+ //lyx::Assert(nucleus());
+ return hasLimits() ? (width() - nwid()) / 2 : 0;
int MathAtom::nwid() const
{
int MathAtom::nwid() const
{
- return nucleus() ? nucleus()->width() : 0;
+ return nucleus() ?
+ nucleus()->width() :
+ mathed_char_width(LM_TC_TEX, LM_ST_TEXT, '.');
yo(y);
if (nucleus())
nucleus()->draw(pain, x + dxx(), y);
yo(y);
if (nucleus())
nucleus()->draw(pain, x + dxx(), y);
+ else
+ drawStr(pain, LM_TC_TEX, LM_ST_TEXT, x + dxx(), y, ".");
if (up())
up()->draw(pain, x + dx1(), y - dy1());
if (down())
if (up())
up()->draw(pain, x + dx1(), y - dy1());
if (down())
+bool MathAtom::hasInner() const
+{
+ return nucleus_ && (script_[0] || script_[1]);
+}
+
+
void MathAtom::substitute(MathMacro const & m)
{
if (nucleus())
void MathAtom::substitute(MathMacro const & m)
{
if (nucleus())
+
+
+void MathAtom::removeNucleus()
+{
+ delete nucleus_;
+ nucleus_ = 0;
+}
+
+
+void MathAtom::removeUp()
+{
+ delete script_[1];
+ script_[1] = 0;
+}
+
+
+void MathAtom::removeDown()
+{
+ delete script_[0];
+ script_[0] = 0;
+}
MathScriptInset * ensure(bool up);
/// delete subscript array if empty
void removeEmptyScripts();
MathScriptInset * ensure(bool up);
/// delete subscript array if empty
void removeEmptyScripts();
+ /// delete nucleus
+ void removeNucleus();
+ /// delete superscript
+ void removeUp();
+ /// delete subscript
+ void removeDown();
/// can we add a super- or subscript?
virtual bool allows(bool up) const { return script_[up] == 0; }
/// can we add a super- or subscript?
/// can we add a super- or subscript?
virtual bool allows(bool up) const { return script_[up] == 0; }
/// can we add a super- or subscript?
int limits() const { return limits_; }
///
bool hasLimits() const;
int limits() const { return limits_; }
///
bool hasLimits() const;
+ /// true if we have an "inner" position
+ bool hasInner() const;
/// returns superscript
MathScriptInset * up() const;
/// returns subscript
/// returns superscript
MathScriptInset * up() const;
/// returns subscript
///
MathInset * nucleus() const { return nucleus_; }
///
///
MathInset * nucleus() const { return nucleus_; }
///
+ MathInset * & nucleus() { return nucleus_; }
+ ///
void substitute(const MathMacro &);
///
void write(std::ostream &, bool) const;
///
void writeNormal(std::ostream &) const;
void substitute(const MathMacro &);
///
void write(std::ostream &, bool) const;
///
void writeNormal(std::ostream &) const;
+ /// returns width of nucleus if any
+ int nwid() const;
protected:
/// possible subscript (index 0) and superscript (index 1)
protected:
/// possible subscript (index 0) and superscript (index 1)
int dy0() const;
/// returns y offset for subscript
int dy1() const;
int dy0() const;
/// returns y offset for subscript
int dy1() const;
+ /// returns x offset for main part
+ int dxx() const;
/// returns x offset for superscript
int dx0() const;
/// returns x offset for subscript
int dx1() const;
/// returns x offset for superscript
int dx0() const;
/// returns x offset for subscript
int dx1() const;
- /// returns x offset for main part
- int dxx() const;
- /// returns width of nucleus if any
- int nwid() const;
/// returns ascent of nucleus if any
int nasc() const;
/// returns descent of nucleus if any
/// returns ascent of nucleus if any
int nasc() const;
/// returns descent of nucleus if any
MathCursorPos i1;
MathCursorPos i2;
cursor.getSelection(i1, i2);
MathCursorPos i1;
MathCursorPos i2;
cursor.getSelection(i1, i2);
- if (i1.idx_ == i2.idx_)
- data_.push_back(MathArray(i1.cell(), i1.pos_, i2.pos_));
+ if (i1.idx_ == i2.idx_) {
+ MathArray ar;
+ if (i1.inner_) {
+ ar.push_back(*i1.at());
+ ar.back().removeNucleus();
+ ++i1.pos_;
+ }
+ ar.push_back(MathArray(i1.cell(), i1.pos_, i2.pos_));
+ if (i2.inner_) {
+ ar.push_back(*i2.at());
+ ar.back().removeUp();
+ ar.back().removeDown();
+ }
+ data_.push_back(ar);
+ }
else {
std::vector<MathInset::idx_type> indices =
i1.par_->idxBetween(i1.idx_, i2.idx_);
else {
std::vector<MathInset::idx_type> indices =
i1.par_->idxBetween(i1.idx_, i2.idx_);
MathCursorPos i1;
MathCursorPos i2;
cursor.getSelection(i1, i2);
MathCursorPos i1;
MathCursorPos i2;
cursor.getSelection(i1, i2);
- if (i1.idx_ == i2.idx_)
+ if (i1.idx_ == i2.idx_) {
+ if (i1.inner_) {
+ i1.inner_ = false;
+ i1.at()->removeUp();
+ i1.at()->removeDown();
+ ++i1.pos_;
+ }
+ if (i2.inner_) {
+ i2.inner_ = false;
+ i2.at()->removeNucleus();
+ }
i1.cell().erase(i1.pos_, i2.pos_);
i1.cell().erase(i1.pos_, i2.pos_);
- else {
- std::vector<MathInset::idx_type> indices = i1.par_->idxBetween(i1.idx_, i2.idx_);
+ } else {
+ std::vector<MathInset::idx_type> indices =
+ i1.par_->idxBetween(i1.idx_, i2.idx_);
for (unsigned i = 0; i < indices.size(); ++i)
i1.cell(indices[i]).erase();
}
for (unsigned i = 0; i < indices.size(); ++i)
i1.cell(indices[i]).erase();
}
std::ostream & operator<<(std::ostream & os, MathCursorPos const & p)
{
os << "(par: " << p.par_ << " idx: " << p.idx_
std::ostream & operator<<(std::ostream & os, MathCursorPos const & p)
{
os << "(par: " << p.par_ << " idx: " << p.idx_
- << " pos: " << p.pos_ << ")";
+ << " pos: " << p.pos_ << " inner: " << p.inner_ << ")";
void MathCursor::pushLeft(MathInset * par)
{
MathCursorPos p;
void MathCursor::pushLeft(MathInset * par)
{
MathCursorPos p;
+ p.par_ = par;
+ p.inner_ = false;
par->idxFirst(p.idx_, p.pos_);
Cursor_.push_back(p);
}
par->idxFirst(p.idx_, p.pos_);
Cursor_.push_back(p);
}
{
posLeft();
MathCursorPos p;
{
posLeft();
MathCursorPos p;
+ p.par_ = par;
+ p.inner_ = false;
par->idxLast(p.idx_, p.pos_);
Cursor_.push_back(p);
}
par->idxLast(p.idx_, p.pos_);
Cursor_.push_back(p);
}
bool MathCursor::posLeft()
{
bool MathCursor::posLeft()
{
+ if (inner()) {
+ inner() = false;
+ return true;
+ }
+
if (pos() == 0)
return false;
if (pos() == 0)
return false;
+
+ if (nextAtom()->hasInner())
+ inner() = true;
+
return true;
}
bool MathCursor::posRight()
{
return true;
}
bool MathCursor::posRight()
{
+ if (inner()) {
+ ++pos();
+ inner() = false;
+ return true;
+ }
+
if (pos() == size())
return false;
if (pos() == size())
return false;
+
+ if (nextAtom()->hasInner())
+ inner() = true;
+ else
+ ++pos();
+
int x1 = x - ar.xo();
int y1 = y - ar.yo();
MathXArray::size_type c = ar.x2pos(x1);
int x1 = x - ar.xo();
int y1 = y - ar.yo();
MathXArray::size_type c = ar.x2pos(x1);
- int xx = abs(x1 - ar.pos2x(c));
+ int xx = abs(x1 - ar.pos2x(c, false));
int yy = abs(y1);
//lyxerr << "idx: " << i << " xx: " << xx << " yy: " << yy
// << " c: " << c << " xo: " << ar.xo() << "\n";
int yy = abs(y1);
//lyxerr << "idx: " << i << " xx: " << xx << " yy: " << yy
// << " c: " << c << " xo: " << ar.xo() << "\n";
+void MathCursor::plainInsert(MathInset * p)
+{
+ if (inner()) {
+ array().insert(pos(), p);
+ ++pos();
+ swap(prevAtom()->nucleus(), nextAtom()->nucleus());
+ return;
+ }
+
+ MathAtom * n = nextAtom();
+
+ if (n && !n->nucleus()) {
+ n->nucleus() = p;
+ inner() = true;
+ return;
+ }
+
+ array().insert(pos(), p); // this invalidates the pointer!
+ ++pos();
+}
+
+
void MathCursor::insert(char c, MathTextCodes t)
{
//lyxerr << "inserting '" << c << "'\n";
void MathCursor::insert(char c, MathTextCodes t)
{
//lyxerr << "inserting '" << c << "'\n";
- array().insert(pos(), new MathCharInset(c, t));
- posRight();
+ plainInsert(new MathCharInset(c, t));
if (p->nargs())
selCut();
else
selDel();
}
if (p->nargs())
selCut();
else
selDel();
}
- array().insert(pos(), p); // this invalidates the pointer!
- p = array().at(pos())->nucleus();
- posRight();
+void MathCursor::glueAdjacentAtoms()
+{
+ MathAtom * p = prevAtom();
+ if (!p)
+ return;
+
+ MathAtom * n = nextAtom();
+ if (!n)
+ return;
+
+ if (p->up() && n->up())
+ return;
+
+ if (p->down() && n->down())
+ return;
+
+ // move everything to the previous atom
+ if (n->up())
+ swap(p->up(), n->up());
+
+ if (n->down())
+ swap(p->down(), n->down());
+
+ plainErase();
+ --pos();
+ inner() = nextAtom()->hasInner();
+}
+
+
void MathCursor::backspace()
{
void MathCursor::backspace()
{
- if (posLeft()) {
- erase();
+ if (inner()) {
+ nextAtom()->removeNucleus();
+ inner() = false;
+ glueAdjacentAtoms();
- if (size()) {
- pullArg(false);
+ if (pos() == 0) {
+ if (size())
+ pullArg(false);
+ return;
+ }
+
+ if (prevAtom()->hasInner()) {
+ --pos();
+ inner() = true;
+ --pos();
+ plainErase();
}
void MathCursor::erase()
{
}
void MathCursor::erase()
{
if (inMacroMode())
return;
if (inMacroMode())
return;
}
// delete empty cells if necessary
}
// delete empty cells if necessary
- if (pos() == 0 && array().empty()) {
bool popit;
bool removeit;
par()->idxDelete(idx(), popit, removeit);
bool popit;
bool removeit;
par()->idxDelete(idx(), popit, removeit);
+ MathAtom * n = nextAtom();
+
+ if (!n)
- // delete nucleus, keep scripts if possible
- MathAtom * p = prevAtom();
- MathAtom * n = nextAtom();
- if (pos() > 0) {
- bool need_parans = (p->up() && n->up()) || (p->down() && n->down());
- if (need_parans) {
- // need empty block
- insert('{', LM_TC_TEX);
- insert('}', LM_TC_TEX);
- p = prevAtom();
- n = nextAtom();
- }
- // move indices to the left
- swap(p->up(), n->up());
- if (n->down())
- swap(p->down(), n->down());
- plainErase();
+ n->removeUp();
+ else if (n->down())
+ n->removeDown();
+ if (!n->up() && !n->down()) {
+ ++pos();
+ inner() = false;
+ }
- // pos == 0 now
- if (n->up() || n->down()) {
- insert('{', LM_TC_TEX);
- insert('}', LM_TC_TEX);
- p = prevAtom();
- n = nextAtom();
- swap(p->up(), n->up());
- swap(p->down(), n->down());
+ if (n->hasInner()) {
+ n->removeNucleus();
+ inner() = true;
+ return;
if (i1.idx_ == i2.idx_) {
MathXArray & c = i1.xcell();
if (i1.idx_ == i2.idx_) {
MathXArray & c = i1.xcell();
- int x1 = c.xo() + c.pos2x(i1.pos_);
+ int x1 = c.xo() + c.pos2x(i1.pos_, i1.inner_);
int y1 = c.yo() - c.ascent();
int y1 = c.yo() - c.ascent();
- int x2 = c.xo() + c.pos2x(i2.pos_);
+ int x2 = c.xo() + c.pos2x(i2.pos_, i2.inner_);
int y2 = c.yo() + c.descent();
pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
} else {
int y2 = c.yo() + c.descent();
pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
} else {
#ifdef WITH_WARNINGS
#warning This should probably take cellXOffset and cellYOffset into account
#endif
#ifdef WITH_WARNINGS
#warning This should probably take cellXOffset and cellYOffset into account
#endif
- x = xarray().xo() + xarray().pos2x(pos());
+ x = xarray().xo() + xarray().pos2x(pos(), inner());
+bool MathCursor::inner() const
+{
+ return cursor().inner_;
+}
+
+
+bool & MathCursor::inner()
+{
+ return cursor().inner_;
+}
+
+
bool MathCursor::inMacroMode() const
{
return lastcode_ == LM_TC_TEX;
bool MathCursor::inMacroMode() const
{
return lastcode_ == LM_TC_TEX;
int MathCursor::xpos() const
{
int MathCursor::xpos() const
{
- return cellXOffset() + xarray().pos2x(pos());
+ return cellXOffset() + xarray().pos2x(pos(), inner());
// we got just a single char now
if (c == '^' || c == '_') {
// we got just a single char now
if (c == '^' || c == '_') {
- bool const up = (s[0] == '^');
- selCut();
- if (!prevInset()) {
- insert('{', LM_TC_TEX);
- insert('}', LM_TC_TEX);
- }
+ const bool up = (s[0] == '^');
+ selCut();
+ if (inner())
+ ++pos();
+ if (!prevAtom())
+ insert(0);
MathInset * par = prevAtom()->ensure(up);
pushRight(par);
selPaste();
MathInset * par = prevAtom()->ensure(up);
pushRight(par);
selPaste();
- if (lastcode_ != LM_TC_TEX && strchr("#$%{}", c)) {
+ if (lastcode_ != LM_TC_TEX && strchr("{}", c)) {
+ insert(c, LM_TC_TEX);
+ return;
+ }
+
+ if (lastcode_ != LM_TC_TEX && strchr("#$%", c)) {
insert(new MathSpecialCharInset(c));
lastcode_ = LM_TC_VAR;
return;
insert(new MathSpecialCharInset(c));
lastcode_ = LM_TC_VAR;
return;
macroModeClose();
lastcode_ = LM_TC_VAR;
}
macroModeClose();
lastcode_ = LM_TC_VAR;
}
else {
macroModeClose();
lastcode_ = LM_TC_VAR;
else {
macroModeClose();
lastcode_ = LM_TC_VAR;
}
// no special circumstances, so insert the character without any fuss
}
// no special circumstances, so insert the character without any fuss
+MathAtom * MathCursorPos::at() const
+{
+ return cell().at(pos_);
+}
+
+
MathCursorPos MathCursor::normalAnchor() const
{
// use Anchor on the same level as Cursor
MathCursorPos MathCursor::normalAnchor() const
{
// use Anchor on the same level as Cursor
MathInset::idx_type idx_;
/// cell position
MathInset::pos_type pos_;
MathInset::idx_type idx_;
/// cell position
MathInset::pos_type pos_;
+ /// faked position "inside an atom"
+ bool inner_;
+
/// returns cell corresponding to this position
MathArray & cell() const;
/// returns cell corresponding to this position
/// returns cell corresponding to this position
MathArray & cell() const;
/// returns cell corresponding to this position
MathXArray & xcell() const;
/// returns xcell corresponding to this position
MathXArray & xcell(MathInset::idx_type idx) const;
MathXArray & xcell() const;
/// returns xcell corresponding to this position
MathXArray & xcell(MathInset::idx_type idx) const;
+
+ /// returns atom corresponding to this position
+ MathAtom * at() const;
void first();
/// Put the cursor in the last position
void last();
void first();
/// Put the cursor in the last position
void last();
- /// moves cursor position one cell to the left
- bool posLeft();
- /// moves cursor position one cell to the right
- bool posRight();
- /// moves cursor index one cell to the left
- bool idxLeft();
- /// moves cursor index one cell to the right
- bool idxRight();
- /// moves position somehow up
- bool goUp();
- /// moves position somehow down
- bool goDown();
void plainInsert(MathInset * p);
///
void niceInsert(MathInset * p);
void plainInsert(MathInset * p);
///
void niceInsert(MathInset * p);
///
void delLine();
/// This is in pixels from (maybe?) the top of inset
///
void delLine();
/// This is in pixels from (maybe?) the top of inset
///
InsetFormulaBase const * formula();
///
///
InsetFormulaBase const * formula();
///
+ bool inner() const;
+ ///
pos_type pos() const;
///
idx_type idx() const;
pos_type pos() const;
///
idx_type idx() const;
MathScriptInset * prevScriptInset() const;
///
MathSpaceInset * prevSpaceInset() const;
MathScriptInset * prevScriptInset() const;
///
MathSpaceInset * prevSpaceInset() const;
+ /// moves cursor position one cell to the left
+ bool posLeft();
+ /// moves cursor position one cell to the right
+ bool posRight();
+ /// moves cursor index one cell to the left
+ bool idxLeft();
+ /// moves cursor index one cell to the right
+ bool idxRight();
+ /// moves position somehow up
+ bool goUp();
+ /// moves position somehow down
+ bool goDown();
+ /// glue adjacent atoms if possible
+ void glueAdjacentAtoms();
+
///
string macroName() const;
///
///
string macroName() const;
///
- void insert(char, MathTextCodes t = LM_TC_MIN);
+ void insert(char, MathTextCodes t);
/// can we enter the inset?
bool openable(MathInset *, bool selection) const;
/// can the setPos routine enter that inset?
MathInset * positionable(MathAtom *, int x, int y) const;
/// can we enter the inset?
bool openable(MathInset *, bool selection) const;
/// can the setPos routine enter that inset?
MathInset * positionable(MathAtom *, int x, int y) const;
+ /// write access to "inner" flag
+ bool & inner();
/// write access to cursor cell position
pos_type & pos();
/// write access to cursor cell index
/// write access to cursor cell position
pos_type & pos();
/// write access to cursor cell index
-int MathXArray::pos2x(size_type targetpos) const
+int MathXArray::pos2x(size_type targetpos, bool inner) const
{
int x = 0;
targetpos = std::min(targetpos, data_.size());
for (size_type pos = 0; pos < targetpos; ++pos)
{
int x = 0;
targetpos = std::min(targetpos, data_.size());
for (size_type pos = 0; pos < targetpos; ++pos)
+ x += width(pos);
+ if (inner)
+ x += innerwidth(targetpos);
+int MathXArray::innerwidth(size_type pos) const
+{
+ MathAtom const * t = data_.at(pos);
+ return t ? t->nwid() : 0;
+}
+
+
std::ostream & operator<<(std::ostream & os, MathXArray const & ar)
{
os << ar.data_;
std::ostream & operator<<(std::ostream & os, MathXArray const & ar)
{
os << ar.data_;
///
int yo() const { return yo_; }
///
///
int yo() const { return yo_; }
///
- int pos2x(size_type pos) const;
+ int pos2x(size_type pos, bool inner) const;
///
size_type x2pos(int pos) const;
///
int width(size_type pos) const;
///
size_type x2pos(int pos) const;
///
int width(size_type pos) const;
+ ///
+ int innerwidth(size_type pos) const;
///
int ascent() const { return ascent_; }
///
int ascent() const { return ascent_; }