2003-09-17 16:44:51 +00:00
|
|
|
|
/**
|
|
|
|
|
* \file cursor.C
|
|
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
|
*
|
2003-11-04 12:36:59 +00:00
|
|
|
|
* \author Andr<EFBFBD> P<EFBFBD>nitz
|
2003-09-17 16:44:51 +00:00
|
|
|
|
*
|
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include "buffer.h"
|
|
|
|
|
#include "BufferView.h"
|
|
|
|
|
#include "cursor.h"
|
|
|
|
|
#include "debug.h"
|
2003-10-29 10:47:21 +00:00
|
|
|
|
#include "dispatchresult.h"
|
2003-11-10 09:06:48 +00:00
|
|
|
|
#include "funcrequest.h"
|
2003-09-17 16:44:51 +00:00
|
|
|
|
#include "iterators.h"
|
2003-11-10 09:06:48 +00:00
|
|
|
|
#include "lfuns.h"
|
2003-09-17 16:44:51 +00:00
|
|
|
|
#include "lyxtext.h"
|
|
|
|
|
#include "paragraph.h"
|
2003-11-13 08:50:26 +00:00
|
|
|
|
#include "lyxrow.h"
|
2003-09-17 16:44:51 +00:00
|
|
|
|
|
|
|
|
|
#include "insets/updatableinset.h"
|
2003-11-10 09:06:48 +00:00
|
|
|
|
#include "insets/insettabular.h"
|
2003-11-04 12:36:59 +00:00
|
|
|
|
#include "insets/insettext.h"
|
|
|
|
|
|
2004-01-16 13:35:10 +00:00
|
|
|
|
#include "mathed/math_data.h"
|
|
|
|
|
|
2003-11-04 12:36:59 +00:00
|
|
|
|
#include <boost/assert.hpp>
|
2003-09-17 16:44:51 +00:00
|
|
|
|
|
|
|
|
|
using std::vector;
|
2003-10-29 12:18:08 +00:00
|
|
|
|
using std::endl;
|
2003-09-17 16:44:51 +00:00
|
|
|
|
|
|
|
|
|
|
2004-01-13 18:08:13 +00:00
|
|
|
|
std::ostream & operator<<(std::ostream & os, LCursor const & cur)
|
2003-11-04 12:36:59 +00:00
|
|
|
|
{
|
2003-11-06 16:43:12 +00:00
|
|
|
|
os << "\n";
|
2004-01-13 18:08:13 +00:00
|
|
|
|
for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
|
|
|
|
|
os << " (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
|
2003-11-04 12:36:59 +00:00
|
|
|
|
return os;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-01-16 10:55:19 +00:00
|
|
|
|
LCursor::LCursor()
|
|
|
|
|
: cursor_(1), anchor_(1), bv_(0)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LCursor::LCursor(BufferView & bv)
|
|
|
|
|
: cursor_(1), anchor_(1), bv_(&bv)
|
2003-11-10 09:06:48 +00:00
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
|
2003-09-17 16:44:51 +00:00
|
|
|
|
{
|
2003-11-10 09:06:48 +00:00
|
|
|
|
lyxerr << "\nLCursor::dispatch: " << *this << endl;
|
|
|
|
|
FuncRequest cmd = cmd0;
|
|
|
|
|
|
2004-01-13 18:08:13 +00:00
|
|
|
|
for (int i = cursor_.size() - 1; i >= 1; --i) {
|
|
|
|
|
CursorSlice const & citem = cursor_[i];
|
2003-11-10 09:06:48 +00:00
|
|
|
|
lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
|
2004-01-15 17:34:44 +00:00
|
|
|
|
DispatchResult res = citem.inset_->dispatch(*bv_, cmd);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
if (res.dispatched()) {
|
|
|
|
|
lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
|
2003-11-06 10:30:43 +00:00
|
|
|
|
return DispatchResult(true, true);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
// remove one level of cursor
|
|
|
|
|
switch (res.val()) {
|
|
|
|
|
case FINISHED:
|
|
|
|
|
pop(i);
|
2004-01-15 17:34:44 +00:00
|
|
|
|
cmd = FuncRequest(LFUN_FINISHED_LEFT);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
break;
|
|
|
|
|
case FINISHED_RIGHT:
|
|
|
|
|
pop(i);
|
2004-01-15 17:34:44 +00:00
|
|
|
|
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
break;
|
2003-11-22 14:44:59 +00:00
|
|
|
|
case FINISHED_UP:
|
2003-11-10 09:06:48 +00:00
|
|
|
|
pop(i);
|
2004-01-15 17:34:44 +00:00
|
|
|
|
cmd = FuncRequest(LFUN_FINISHED_UP);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
break;
|
|
|
|
|
case FINISHED_DOWN:
|
|
|
|
|
pop(i);
|
2004-01-15 17:34:44 +00:00
|
|
|
|
cmd = FuncRequest(LFUN_FINISHED_DOWN);
|
2003-11-10 09:06:48 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-09-17 16:44:51 +00:00
|
|
|
|
}
|
2003-11-28 08:55:12 +00:00
|
|
|
|
lyxerr << "trying to dispatch to main text " << bv_->text() << endl;
|
2004-01-15 17:34:44 +00:00
|
|
|
|
DispatchResult res = bv_->text()->dispatch(*bv_, cmd);
|
2003-11-04 12:36:59 +00:00
|
|
|
|
lyxerr << " result: " << res.val() << endl;
|
2003-11-14 18:15:58 +00:00
|
|
|
|
|
|
|
|
|
if (!res.dispatched()) {
|
|
|
|
|
lyxerr << "trying to dispatch to bv " << bv_ << endl;
|
|
|
|
|
bool sucess = bv_->dispatch(cmd);
|
|
|
|
|
lyxerr << " result: " << sucess << endl;
|
|
|
|
|
res.dispatched(sucess);
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-04 12:36:59 +00:00
|
|
|
|
return res;
|
2003-09-17 16:44:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-01-15 17:34:44 +00:00
|
|
|
|
void LCursor::push(InsetBase * inset)
|
2003-11-06 10:30:43 +00:00
|
|
|
|
{
|
2003-11-10 09:06:48 +00:00
|
|
|
|
lyxerr << "LCursor::push() inset: " << inset << endl;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
cursor_.push_back(CursorSlice(inset));
|
|
|
|
|
anchor_.push_back(CursorSlice(inset));
|
2003-11-18 11:39:30 +00:00
|
|
|
|
updatePos();
|
2003-11-06 10:30:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-01-13 11:33:22 +00:00
|
|
|
|
|
2003-11-10 09:06:48 +00:00
|
|
|
|
void LCursor::pop(int depth)
|
2003-09-17 16:44:51 +00:00
|
|
|
|
{
|
2003-11-10 09:06:48 +00:00
|
|
|
|
lyxerr << "LCursor::pop() to " << depth << endl;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
while (cursor_.size() > 1 && depth < cursor_.size()) {
|
2003-11-10 09:06:48 +00:00
|
|
|
|
lyxerr << "LCursor::pop a level " << endl;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
cursor_.pop_back();
|
|
|
|
|
anchor_.pop_back();
|
2003-11-10 09:06:48 +00:00
|
|
|
|
}
|
2003-11-04 12:36:59 +00:00
|
|
|
|
}
|
2003-09-17 16:44:51 +00:00
|
|
|
|
|
|
|
|
|
|
2003-11-04 12:36:59 +00:00
|
|
|
|
void LCursor::pop()
|
|
|
|
|
{
|
2003-11-06 16:43:12 +00:00
|
|
|
|
lyxerr << "LCursor::pop() " << endl;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
//BOOST_ASSERT(!cursor_.empty());
|
|
|
|
|
if (cursor_.size() <= 1)
|
2003-11-06 11:56:10 +00:00
|
|
|
|
lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
else {
|
|
|
|
|
cursor_.pop_back();
|
|
|
|
|
anchor_.pop_back();
|
|
|
|
|
}
|
2003-11-04 12:36:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-11-10 09:06:48 +00:00
|
|
|
|
UpdatableInset * LCursor::innerInset() const
|
2003-11-04 12:36:59 +00:00
|
|
|
|
{
|
2004-01-13 18:08:13 +00:00
|
|
|
|
return cursor_.size() <= 1 ? 0 : cursor_.back().asUpdatableInset();
|
2003-11-04 12:36:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LyXText * LCursor::innerText() const
|
|
|
|
|
{
|
2004-01-13 18:08:13 +00:00
|
|
|
|
if (cursor_.size() > 1) {
|
2003-11-10 09:06:48 +00:00
|
|
|
|
// go up until first non-0 text is hit
|
|
|
|
|
// (innermost text is 0 e.g. for mathed and the outer tabular level)
|
2004-01-13 18:08:13 +00:00
|
|
|
|
for (int i = cursor_.size() - 1; i >= 1; --i)
|
|
|
|
|
if (cursor_[i].text())
|
|
|
|
|
return cursor_[i].text();
|
2003-11-10 09:06:48 +00:00
|
|
|
|
}
|
2003-11-28 08:55:12 +00:00
|
|
|
|
return bv_->text();
|
2003-11-10 09:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:17:28 +00:00
|
|
|
|
void LCursor::updatePos()
|
|
|
|
|
{
|
2004-01-13 18:08:13 +00:00
|
|
|
|
if (cursor_.size() > 1)
|
2004-01-16 10:55:19 +00:00
|
|
|
|
cached_y_ = bv_->top_y() + cursor_.back().inset()->y();
|
2003-11-11 13:17:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 08:50:26 +00:00
|
|
|
|
void LCursor::getDim(int & asc, int & desc) const
|
|
|
|
|
{
|
|
|
|
|
LyXText * txt = innerText();
|
2003-11-22 14:44:59 +00:00
|
|
|
|
|
2003-11-13 08:50:26 +00:00
|
|
|
|
if (txt) {
|
|
|
|
|
Row const & row = *txt->cursorRow();
|
|
|
|
|
asc = row.baseline();
|
|
|
|
|
desc = row.height() - asc;
|
2004-01-16 10:55:19 +00:00
|
|
|
|
} else {
|
2003-11-21 14:59:24 +00:00
|
|
|
|
innerInset()->getCursorDim(asc, desc);
|
2004-01-16 10:55:19 +00:00
|
|
|
|
}
|
2003-11-13 08:50:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-11-10 09:06:48 +00:00
|
|
|
|
void LCursor::getPos(int & x, int & y) const
|
|
|
|
|
{
|
2004-01-13 18:08:13 +00:00
|
|
|
|
if (cursor_.size() <= 1) {
|
2003-12-15 11:36:19 +00:00
|
|
|
|
x = bv_->text()->cursorX();
|
|
|
|
|
y = bv_->text()->cursorY();
|
2003-11-11 09:06:41 +00:00
|
|
|
|
// y -= bv_->top_y();
|
2003-11-10 09:06:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
// Would be nice to clean this up to make some understandable sense...
|
|
|
|
|
UpdatableInset * inset = innerInset();
|
|
|
|
|
// Non-obvious. The reason we have to have these
|
|
|
|
|
// extra checks is that the ->getCursor() calls rely
|
|
|
|
|
// on the inset's own knowledge of its screen position.
|
|
|
|
|
// If we scroll up or down in a big enough increment, the
|
|
|
|
|
// inset->draw() is not called: this doesn't update
|
|
|
|
|
// inset.top_baseline, so getCursor() returns an old value.
|
|
|
|
|
// Ugly as you like.
|
2004-01-15 17:34:44 +00:00
|
|
|
|
if (inset) {
|
|
|
|
|
inset->getCursorPos(cursor_.back().idx_, x, y);
|
|
|
|
|
x += inset->x();
|
|
|
|
|
y += cached_y_;
|
|
|
|
|
}
|
2003-11-10 09:06:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UpdatableInset * LCursor::innerInsetOfType(int code) const
|
|
|
|
|
{
|
2004-01-13 18:08:13 +00:00
|
|
|
|
for (int i = cursor_.size() - 1; i >= 1; --i)
|
|
|
|
|
if (cursor_[i].asUpdatableInset()->lyxCode() == code)
|
|
|
|
|
return cursor_[i].asUpdatableInset();
|
2003-11-10 09:06:48 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-22 14:44:59 +00:00
|
|
|
|
|
2003-11-10 09:06:48 +00:00
|
|
|
|
InsetTabular * LCursor::innerInsetTabular() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<InsetTabular *>
|
|
|
|
|
(innerInsetOfType(InsetOld::TABULAR_CODE));
|
2003-09-17 16:44:51 +00:00
|
|
|
|
}
|
2004-01-08 18:30:14 +00:00
|
|
|
|
|
|
|
|
|
|
2004-01-16 12:36:23 +00:00
|
|
|
|
void LCursor::resetAnchor()
|
2004-01-08 18:30:14 +00:00
|
|
|
|
{
|
2004-01-16 12:36:23 +00:00
|
|
|
|
anchor_ = cursor_;
|
2004-01-13 18:08:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-01-16 12:36:23 +00:00
|
|
|
|
BufferView & LCursor::bv() const
|
2004-01-13 18:08:13 +00:00
|
|
|
|
{
|
2004-01-16 12:36:23 +00:00
|
|
|
|
return *bv_;
|
2004-01-08 18:30:14 +00:00
|
|
|
|
}
|
2004-01-16 13:35:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MathAtom const & LCursor::prevAtom() const
|
|
|
|
|
{
|
|
|
|
|
BOOST_ASSERT(pos() > 0);
|
|
|
|
|
return cell()[pos() - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MathAtom & LCursor::prevAtom()
|
|
|
|
|
{
|
|
|
|
|
BOOST_ASSERT(pos() > 0);
|
|
|
|
|
return cell()[pos() - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MathAtom const & LCursor::nextAtom() const
|
|
|
|
|
{
|
|
|
|
|
BOOST_ASSERT(pos() < lastpos());
|
|
|
|
|
return cell()[pos()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MathAtom & LCursor::nextAtom()
|
|
|
|
|
{
|
|
|
|
|
BOOST_ASSERT(pos() < lastpos());
|
|
|
|
|
return cell()[pos()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool LCursor::posLeft()
|
|
|
|
|
{
|
|
|
|
|
if (pos() == 0)
|
|
|
|
|
return false;
|
|
|
|
|
--pos();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool LCursor::posRight()
|
|
|
|
|
{
|
|
|
|
|
if (pos() == lastpos())
|
|
|
|
|
return false;
|
|
|
|
|
++pos();
|
|
|
|
|
return true;
|
|
|
|
|
}
|