3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
14 #include "BufferView.h"
17 #include "dispatchresult.h"
18 #include "funcrequest.h"
19 #include "iterators.h"
22 #include "paragraph.h"
25 #include "insets/updatableinset.h"
26 #include "insets/insettabular.h"
27 #include "insets/insettext.h"
29 #include "mathed/math_data.h"
30 #include "mathed/math_inset.h"
32 #include <boost/assert.hpp>
38 LCursor::LCursor(BufferView & bv)
39 : cursor_(1), anchor_(1), bv_(&bv), current_(0),
40 cached_y_(0), x_target_(-1),
41 selection_(false), mark_(false)
45 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
47 lyxerr << "\nLCursor::dispatch: " << *this << endl;
48 FuncRequest cmd = cmd0;
50 for (int i = cursor_.size() - 1; i >= 1; --i) {
52 CursorSlice const & citem = cursor_[i];
53 lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
54 DispatchResult res = inset()->dispatch(*this, cmd);
55 if (res.dispatched()) {
56 lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
57 return DispatchResult(true, true);
59 // remove one level of cursor
63 cmd = FuncRequest(LFUN_FINISHED_LEFT);
67 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
71 cmd = FuncRequest(LFUN_FINISHED_UP);
75 cmd = FuncRequest(LFUN_FINISHED_DOWN);
78 lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
82 lyxerr << "trying to dispatch to main text " << bv_->text() << endl;
83 DispatchResult res = bv_->text()->dispatch(*this, cmd);
84 lyxerr << " result: " << res.val() << endl;
86 if (!res.dispatched()) {
87 lyxerr << "trying to dispatch to bv " << bv_ << endl;
88 bool sucess = bv_->dispatch(cmd);
89 lyxerr << " result: " << sucess << endl;
90 res.dispatched(sucess);
97 void LCursor::push(InsetBase * inset)
99 lyxerr << "LCursor::push() inset: " << inset << endl;
100 cursor_.push_back(CursorSlice(inset));
101 anchor_.push_back(CursorSlice(inset));
107 void LCursor::pop(int depth)
109 lyxerr << "LCursor::pop() to depth " << depth << endl;
110 while (cursor_.size() > depth)
117 lyxerr << "LCursor::pop() a level" << endl;
118 //BOOST_ASSERT(!cursor_.empty());
119 if (cursor_.size() <= 1)
120 lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
124 current_ = cursor_.size() - 1;
126 lyxerr << "LCursor::pop() current now: " << current_ << endl;
130 CursorSlice & LCursor::current()
132 //lyxerr << "accessing cursor slice " << current_
133 // << ": " << cursor_[current_] << endl;
134 return cursor_[current_];
138 CursorSlice const & LCursor::current() const
140 //lyxerr << "accessing cursor slice " << current_
141 // << ": " << cursor_[current_] << endl;
142 return cursor_[current_];
146 LyXText * LCursor::innerText() const
148 //lyxerr << "LCursor::innerText() depth: " << cursor_.size() << endl;
149 if (cursor_.size() > 1) {
150 // go up until first non-0 text is hit
151 // (innermost text is 0 e.g. for mathed and the outer tabular level)
152 for (int i = cursor_.size() - 1; i >= 1; --i)
153 if (cursor_[i].text())
154 return cursor_[i].text();
160 void LCursor::updatePos()
162 if (cursor_.size() > 1)
163 cached_y_ = bv_->top_y() + cursor_.back().inset()->y();
167 void LCursor::getDim(int & asc, int & desc) const
169 LyXText * txt = innerText();
172 Row const & row = *txt->cursorRow();
173 asc = row.baseline();
174 desc = row.height() - asc;
178 //innerInset()->getCursorDim(asc, desc);
183 void LCursor::getPos(int & x, int & y) const
185 if (cursor_.size() <= 1) {
186 x = bv_->text()->cursorX();
187 y = bv_->text()->cursorY();
188 // y -= bv_->top_y();
190 if (inset()->asUpdatableInset()) {
191 // Would be nice to clean this up to make some understandable sense...
192 // Non-obvious. The reason we have to have these
193 // extra checks is that the ->getCursor() calls rely
194 // on the inset's own knowledge of its screen position.
195 // If we scroll up or down in a big enough increment, the
196 // inset->draw() is not called: this doesn't update
197 // inset.top_baseline, so getCursor() returns an old value.
199 inset()->asUpdatableInset()->getCursorPos(cursor_.back().idx_, x, y);
200 x += inset()->asUpdatableInset()->x();
202 } else if (inset()->asMathInset()) {
207 // this should not happen
214 InsetBase * LCursor::innerInsetOfType(int code) const
216 for (int i = cursor_.size() - 1; i >= 1; --i)
217 if (cursor_[i].inset_->lyxCode() == code)
218 return cursor_[i].inset_;
223 InsetTabular * LCursor::innerInsetTabular() const
225 return static_cast<InsetTabular *>(innerInsetOfType(InsetBase::TABULAR_CODE));
229 void LCursor::resetAnchor()
235 BufferView & LCursor::bv() const
241 MathAtom const & LCursor::prevAtom() const
243 BOOST_ASSERT(pos() > 0);
244 return cell()[pos() - 1];
248 MathAtom & LCursor::prevAtom()
250 BOOST_ASSERT(pos() > 0);
251 return cell()[pos() - 1];
255 MathAtom const & LCursor::nextAtom() const
257 BOOST_ASSERT(pos() < lastpos());
258 return cell()[pos()];
262 MathAtom & LCursor::nextAtom()
264 BOOST_ASSERT(pos() < lastpos());
265 return cell()[pos()];
269 bool LCursor::posLeft()
278 bool LCursor::posRight()
280 if (pos() == lastpos())
287 CursorSlice & LCursor::anchor()
289 return anchor_.back();
293 CursorSlice const & LCursor::anchor() const
295 return anchor_.back();
299 CursorSlice const & LCursor::selStart() const
302 return cursor_.back();
303 // can't use std::min as this creates a new object
304 return anchor() < cursor_.back() ? anchor() : cursor_.back();
308 CursorSlice const & LCursor::selEnd() const
311 return cursor_.back();
312 return anchor() > cursor_.back() ? anchor() : cursor_.back();
316 CursorSlice & LCursor::selStart()
319 return cursor_.back();
320 return anchor() < cursor_.back() ? anchor() : cursor_.back();
324 CursorSlice & LCursor::selEnd()
327 return cursor_.back();
328 return anchor() > cursor_.back() ? anchor() : cursor_.back();
332 void LCursor::setSelection()
335 // a selection with no contents is not a selection
336 if (par() == anchor().par() && pos() == anchor().pos())
341 void LCursor::clearSelection()
356 void increment(CursorBase & it)
358 CursorSlice & top = it.back();
359 MathArray & ar = top.asMathInset()->cell(top.idx_);
361 // move into the current inset if possible
362 // it is impossible for pos() == size()!
364 if (top.pos() != top.lastpos())
365 n = (ar.begin() + top.pos_)->nucleus();
366 if (n && n->isActive()) {
367 it.push_back(CursorSlice(n));
371 // otherwise move on one cell back if possible
372 if (top.pos() < top.lastpos()) {
373 // pos() == lastpos() is valid!
378 // otherwise try to move on one cell if possible
379 while (top.idx_ + 1 < top.asMathInset()->nargs()) {
380 // idx() == nargs() is _not_ valid!
382 if (top.asMathInset()->validCell(top.idx_)) {
388 // otherwise leave array, move on one back
389 // this might yield pos() == size(), but that's a ok.
391 // it certainly invalidates top
396 CursorBase ibegin(InsetBase * p)
399 it.push_back(CursorSlice(p));
404 CursorBase iend(InsetBase * p)
407 it.push_back(CursorSlice(p));
408 CursorSlice & top = it.back();
409 top.idx_ = top.asMathInset()->nargs() - 1;
410 top.pos_ = top.asMathInset()->cell(top.idx_).size();
415 void LCursor::x_target(int x)
421 int LCursor::x_target() const
427 Paragraph & LCursor::paragraph()
429 return current_ ? current().paragraph() : *bv_->text()->getPar(par());
433 Paragraph const & LCursor::paragraph() const
435 return current_ ? current().paragraph() : *bv_->text()->getPar(par());
439 LCursor::pos_type LCursor::lastpos() const
441 return current_ ? current().lastpos() : bv_->text()->getPar(par())->size();
445 size_t LCursor::nargs() const
447 // assume 1x1 grid for 'plain text'
448 return current_ ? current().nargs() : 1;
452 size_t LCursor::ncols() const
454 // assume 1x1 grid for 'plain text'
455 return current_ ? current().ncols() : 1;
459 size_t LCursor::nrows() const
461 // assume 1x1 grid for 'plain text'
462 return current_ ? current().nrows() : 1;
466 LCursor::row_type LCursor::row() const
468 BOOST_ASSERT(current_ > 0);
469 return current().row();
473 LCursor::col_type LCursor::col() const
475 BOOST_ASSERT(current_ > 0);
476 return current().col();
480 MathArray const & LCursor::cell() const
482 BOOST_ASSERT(current_ > 0);
483 return current().cell();
487 MathArray & LCursor::cell()
489 BOOST_ASSERT(current_ > 0);
490 return current().cell();
494 void LCursor::info(std::ostream & os)
496 for (int i = 1, n = depth(); i < n; ++i) {
497 cursor_[i].inset()->infoize(os);
502 // prevAtom()->infoize2(os);
503 // overwite old message
508 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
511 for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
512 os << " (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";