* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
- * \author Jürgen Vigna
+ * \author André Pönitz
*
* Full author contact details are available in file CREDITS.
*/
#include "cursor.h"
#include "debug.h"
#include "dispatchresult.h"
+#include "funcrequest.h"
#include "iterators.h"
+#include "lfuns.h"
#include "lyxtext.h"
#include "paragraph.h"
#include "insets/updatableinset.h"
+#include "insets/insettabular.h"
+#include "insets/insettext.h"
+
+#include <boost/assert.hpp>
using std::vector;
using std::endl;
-DispatchResult Cursor::dispatch(FuncRequest const & cmd)
+std::ostream & operator<<(std::ostream & os, CursorItem const & item)
{
- for (int i = data_.size() - 1; i >= 0; --i) {
- lyxerr << "trying to dispatch to inset" << data_[i].inset_ << endl;
- DispatchResult res = data_[i].inset_->dispatch(cmd);
- lyxerr << " result: " << res.val() << endl;
+ os << " inset: " << item.inset_
+ << " text: " << item.text()
+// << " par: " << item.par_
+// << " pos: " << item.pos_
+ << " x: " << item.inset_->x()
+ << " y: " << item.inset_->y()
+;
+ return os;
+}
+
+
+LyXText * CursorItem::text() const
+{
+ return inset_->getText(0);
+}
+
+
+std::ostream & operator<<(std::ostream & os, LCursor const & cursor)
+{
+ os << "\n";
+ for (size_t i = 0, n = cursor.data_.size(); i != n; ++i)
+ os << " " << cursor.data_[i] << "\n";
+ return os;
+}
- if (res.dispatched())
- return res;
- lyxerr << "# unhandled result: " << res.val() << endl;
+LCursor::LCursor(BufferView * bv)
+ : bv_(bv)
+{}
+
+
+DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
+{
+ lyxerr << "\nLCursor::dispatch: " << *this << endl;
+ FuncRequest cmd = cmd0;
+
+ for (int i = data_.size() - 1; i >= 0; --i) {
+ CursorItem const & citem = data_[i];
+ lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
+ DispatchResult res = citem.inset_->dispatch(cmd);
+ if (res.update())
+ bv_->update();
+ if (res.dispatched()) {
+ lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
+ return DispatchResult(true, true);
+ }
+ // remove one level of cursor
+ switch (res.val()) {
+ case FINISHED:
+ pop(i);
+ cmd = FuncRequest(bv_, LFUN_FINISHED_LEFT);
+ break;
+ case FINISHED_RIGHT:
+ pop(i);
+ cmd = FuncRequest(bv_, LFUN_FINISHED_RIGHT);
+ break;
+ case FINISHED_UP:
+ pop(i);
+ cmd = FuncRequest(bv_, LFUN_FINISHED_UP);
+ break;
+ case FINISHED_DOWN:
+ pop(i);
+ cmd = FuncRequest(bv_, LFUN_FINISHED_DOWN);
+ break;
+ default:
+ lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
+ break;
+ }
}
- return DispatchResult(false);
+ lyxerr << "trying to dispatch to main text " << bv_->text << endl;
+ DispatchResult res = bv_->text->dispatch(cmd);
+ lyxerr << " result: " << res.val() << endl;
+ return res;
}
-void buildCursor(Cursor & cursor, BufferView & bv)
+void LCursor::push(UpdatableInset * inset)
{
- UpdatableInset * inset = bv.theLockingInset();
- lyxerr << "\nbuildCursor: " << inset << endl;
- if (!inset)
- return;
-
- inset = inset->getLockingInset();
-
- bool ok = false;
- ParIterator pit = bv.buffer()->par_iterator_begin();
- ParIterator end = bv.buffer()->par_iterator_end();
- for ( ; pit != end && !ok; ++pit) {
- InsetList::iterator it = pit->insetlist.begin();
- InsetList::iterator iend = pit->insetlist.end();
- for ( ; it != iend && !ok; ++it)
- if (it->inset == inset || it->inset == inset->owner())
- ok = true;
+ lyxerr << "LCursor::push() inset: " << inset << endl;
+ data_.push_back(CursorItem(inset));
+}
+
+
+void LCursor::pop(int depth)
+{
+ lyxerr << "LCursor::pop() to " << depth << endl;
+ while (depth < data_.size()) {
+ lyxerr << "LCursor::pop a level " << endl;
+ data_.pop_back();
}
+}
- if (!ok) {
- lyxerr << " tli not found! inset: " << inset << endl;
- return;
+
+void LCursor::pop()
+{
+ lyxerr << "LCursor::pop() " << endl;
+ //BOOST_ASSERT(!data_.empty());
+ if (data_.empty())
+ lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
+ else
+ data_.pop_back();
+}
+
+
+UpdatableInset * LCursor::innerInset() const
+{
+ return data_.empty() ? 0 : data_.back().inset_;
+}
+
+
+LyXText * LCursor::innerText() const
+{
+ if (!data_.empty()) {
+ // go up until first non-0 text is hit
+ // (innermost text is 0 e.g. for mathed and the outer tabular level)
+ for (int i = data_.size() - 1; i >= 0; --i)
+ if (data_[i].text())
+ return data_[i].text();
}
+ return bv_->text;
+}
+
- pit.asCursor(cursor);
- for (size_t i = 0, n = cursor.data_.size(); i != n; ++i) {
- lyxerr << " inset: " << cursor.data_[i].inset_
- << " idx: " << cursor.data_[i].idx_
- << " text: " << cursor.data_[i].text_
- << " par: " << cursor.data_[i].par_
- << " pos: " << cursor.data_[i].pos_
- << endl;
+void LCursor::getPos(int & x, int & y) const
+{
+ if (data_.empty()) {
+ x = bv_->text->cursor.x();
+ y = bv_->text->cursor.y();
+ y -= bv_->top_y();
+ } 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.
+ //inset->getCursorPos(bv_, x, y);
+ //y = inset->insetInInsetY() + bv_->text->cursor.y();
+ inset->getCursorPos(bv_, x, y);
+ x += inset->x();
+ y += inset->y();
}
}
+
+
+UpdatableInset * LCursor::innerInsetOfType(int code) const
+{
+ for (int i = data_.size() - 1; i >= 0; --i)
+ if (data_[i].inset_->lyxCode() == code)
+ return data_[i].inset_;
+ return 0;
+}
+
+
+InsetTabular * LCursor::innerInsetTabular() const
+{
+ return static_cast<InsetTabular *>
+ (innerInsetOfType(InsetOld::TABULAR_CODE));
+}