X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FCursor.cpp;h=ac230a15e003cb2ca9ad18163e97f0e583bbce02;hb=09df753df4c24470617c64d25eae6df2db85dfed;hp=74a0cd2e4937317ac98b204cffc7ef0693109afe;hpb=fc6ce7cd08562fd7bab4427880b46390bb7d2f07;p=lyx.git diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 74a0cd2e49..ac230a15e0 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -6,14 +6,15 @@ * \author Alejandro Aguilar Sierra * \author Alfredo Braunstein * \author André Pönitz + * \author Stefan Schimanski * * Full author contact details are available in file CREDITS. */ #include +#include "Bidi.h" #include "BufferView.h" -#include "bufferview_funcs.h" #include "Buffer.h" #include "Cursor.h" #include "CoordCache.h" @@ -28,20 +29,20 @@ #include "LyXFunc.h" // only for setMessage() #include "LyXRC.h" #include "Row.h" -#include "LyXText.h" +#include "Text.h" #include "Paragraph.h" #include "paragraph_funcs.h" #include "ParIterator.h" +#include "TextMetrics.h" #include "insets/InsetTabular.h" #include "insets/InsetText.h" -#include "mathed/MathData.h" #include "mathed/InsetMath.h" #include "mathed/InsetMathScript.h" #include "mathed/MacroTable.h" - -#include "support/limited_stack.h" +#include "mathed/MathData.h" +#include "mathed/MathMacro.h" #include #include @@ -51,14 +52,15 @@ #include #include -namespace lyx { - using std::string; using std::vector; using std::endl; using std::min; using std::for_each; + +namespace lyx { + namespace { bool @@ -94,9 +96,9 @@ namespace { int xo; int yo; Inset const * inset = &it.inset(); - std::map const & data = + std::map const & data = c.bv().coordCache().getInsets().getData(); - std::map::const_iterator I = data.find(inset); + std::map::const_iterator I = data.find(inset); // FIXME: in the case where the inset is not in the cache, this // means that no part of it is visible on screen. In this case @@ -107,7 +109,7 @@ namespace { return it; } - Point o = I->second; + Point o = I->second.pos; inset->cursorPos(c.bv(), it.top(), c.boundary(), xo, yo); // Convert to absolute xo += o.x_; @@ -129,6 +131,7 @@ namespace { } + /* /// moves position closest to (x, y) in given box bool bruteFind(Cursor & cursor, int x, int y, int xlow, int xhigh, int ylow, int yhigh) @@ -158,7 +161,7 @@ namespace { for ( ; it != et; it.forwardPos(true)) { // avoid invalid nesting when selecting if (!cursor.selection() || positionable(it, cursor.anchor_)) { - Point p = bv_funcs::getPos(bv, it, false); + Point p = bv.getPos(it, false); int xo = p.x_; int yo = p.y_; if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) { @@ -183,6 +186,7 @@ namespace { return false; } + */ /// moves position closest to (x, y) in given box @@ -203,7 +207,7 @@ namespace { // << " xlow: " << xlow << " xhigh: " << xhigh // << " ylow: " << ylow << " yhigh: " << yhigh // << endl; - Inset & inset = bv.buffer()->inset(); + Inset & inset = bv.buffer().inset(); DocIterator it = doc_iterator_begin(inset); it.pit() = from; DocIterator et = doc_iterator_end(inset); @@ -213,9 +217,9 @@ namespace { for ( ; it != et; it.forwardPos()) { // avoid invalid nesting when selecting - if (bv_funcs::status(&bv, it) == bv_funcs::CUR_INSIDE + if (bv.cursorStatus(it) == CUR_INSIDE && (!cur.selection() || positionable(it, cur.anchor_))) { - Point p = bv_funcs::getPos(bv, it, false); + Point p = bv.getPos(it, false); int xo = p.x_; int yo = p.y_; if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) { @@ -245,14 +249,26 @@ namespace { return true; } + docstring parbreak(Paragraph const & par) + { + odocstringstream ods; + ods << '\n'; + // only add blank line if we're not in an ERT or Listings inset + if (par.ownerCode() != ERT_CODE + && par.ownerCode() != LISTINGS_CODE) + ods << '\n'; + return ods.str(); + } + } // namespace anon // be careful: this is called from the bv's constructor, too, so // bv functions are not yet available! Cursor::Cursor(BufferView & bv) - : DocIterator(), bv_(&bv), anchor_(), x_target_(-1), - selection_(false), mark_(false), logicalpos_(false) + : DocIterator(), bv_(&bv), anchor_(), x_target_(-1), textTargetOffset_(0), + selection_(false), mark_(false), logicalpos_(false), + current_font(inherit_font) {} @@ -285,7 +301,10 @@ void Cursor::dispatch(FuncRequest const & cmd0) fixIfBroken(); FuncRequest cmd = cmd0; Cursor safe = *this; - + + // store some values to be used inside of the handlers + getPos(beforeDispX_, beforeDispY_); + beforeDispatchCursor_ = *this; for (; depth(); pop()) { LYXERR(Debug::DEBUG) << "Cursor::dispatch: cmd: " << cmd0 << endl << *this << endl; @@ -302,6 +321,7 @@ void Cursor::dispatch(FuncRequest const & cmd0) if (disp_.dispatched()) break; } + // it completely to get a 'bomb early' behaviour in case this // object will be used again. if (!disp_.dispatched()) { @@ -309,6 +329,10 @@ void Cursor::dispatch(FuncRequest const & cmd0) operator=(safe); disp_.update(Update::None); disp_.dispatched(false); + } else { + // restore the previous one because nested Cursor::dispatch calls + // are possible which would change it + beforeDispatchCursor_ = safe.beforeDispatchCursor_; } } @@ -329,8 +353,7 @@ BufferView & Cursor::bv() const Buffer & Cursor::buffer() const { BOOST_ASSERT(bv_); - BOOST_ASSERT(bv_->buffer()); - return *bv_->buffer(); + return bv_->buffer(); } @@ -396,7 +419,7 @@ int Cursor::currentMode() void Cursor::getPos(int & x, int & y) const { - Point p = bv_funcs::getPos(bv(), *this, boundary()); + Point p = bv().getPos(*this, boundary()); x = p.x_; y = p.y_; } @@ -490,9 +513,7 @@ void Cursor::setSelection() { selection() = true; // A selection with no contents is not a selection -#ifdef WITH_WARNINGS -#warning doesnt look ok -#endif + // FIXME: doesnt look ok if (pit() == anchor().pit() && pos() == anchor().pos()) selection() = false; } @@ -515,9 +536,10 @@ void Cursor::clearSelection() } -int & Cursor::x_target() +void Cursor::setTargetX(int x) { - return x_target_; + x_target_ = x; + textTargetOffset_ = 0; } @@ -530,9 +552,18 @@ int Cursor::x_target() const void Cursor::clearTargetX() { x_target_ = -1; + textTargetOffset_ = 0; } +void Cursor::updateTextTargetOffset() +{ + int x; + int y; + getPos(x, y); + textTargetOffset_ = x - x_target_; +} + void Cursor::info(odocstream & os) const { @@ -557,9 +588,11 @@ bool Cursor::selHandle(bool sel) if (sel == selection()) return false; + if (!sel) + cap::saveSelection(*this); + resetAnchor(); selection() = sel; - cap::saveSelection(*this); return true; } @@ -642,17 +675,17 @@ bool Cursor::openable(MathAtom const & t) const // we can't move into anything new during selection if (depth() >= anchor_.depth()) return false; - if (!ptr_cmp(t.nucleus(), &anchor_[depth()].inset())) + if (t.nucleus() != &anchor_[depth()].inset()) return false; return true; } -void Cursor::setScreenPos(int x, int y) +void Cursor::setScreenPos(int x, int /*y*/) { - x_target() = x; - bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight()); + setTargetX(x); + //bruteFind(*this, x, y, 0, bv().workWidth(), 0, bv().workHeight()); } @@ -774,7 +807,7 @@ bool Cursor::backspace() // If empty cell, and not part of a big cell if (lastpos() == 0 && inset().nargs() == 1) { popLeft(); - // Directly delete empty cell: [|[]] => [|] + // Directly delete empty cell: [|[]] => [|] if (inMathed()) { plainErase(); resetAnchor(); @@ -833,7 +866,7 @@ bool Cursor::erase() bool one_cell = inset().nargs() == 1; if (one_cell && lastpos() == 0) { popLeft(); - // Directly delete empty cell: [|[]] => [|] + // Directly delete empty cell: [|[]] => [|] if (inMathed()) { plainErase(); resetAnchor(); @@ -865,11 +898,13 @@ bool Cursor::up() { macroModeClose(); DocIterator save = *this; - if (goUpDown(true)) + FuncRequest cmd(selection() ? LFUN_UP_SELECT : LFUN_UP, docstring()); + this->dispatch(cmd); + if (disp_.dispatched()) return true; setCursor(save); autocorrect() = false; - return selection(); + return false; } @@ -877,11 +912,13 @@ bool Cursor::down() { macroModeClose(); DocIterator save = *this; - if (goUpDown(false)) + FuncRequest cmd(selection() ? LFUN_DOWN_SELECT : LFUN_DOWN, docstring()); + this->dispatch(cmd); + if (disp_.dispatched()) return true; setCursor(save); autocorrect() = false; - return selection(); + return false; } @@ -907,7 +944,13 @@ bool Cursor::macroModeClose() InsetMathNest * const in = inset().asInsetMath()->asNestInset(); if (in && in->interpretString(*this, s)) return true; - plainInsert(createInsetMath(name)); + MathAtom atom = createInsetMath(name); + MathMacro * atomAsMacro = atom.nucleus()->asMacro(); + if (atomAsMacro) { + // make non-greedy, i.e. don't eat parameters from the right + atomAsMacro->setDisplayMode(MathMacro::DISPLAY_NONGREEDY_INIT); + } + plainInsert(atom); return true; } @@ -940,17 +983,25 @@ int Cursor::targetX() const } +int Cursor::textTargetOffset() const +{ + return textTargetOffset_; +} + + void Cursor::setTargetX() { int x; int y; getPos(x, y); - x_target_ = x; + setTargetX(x); } bool Cursor::inMacroMode() const { + if (!inMathed()) + return false; if (pos() == 0) return false; InsetMathUnknown const * p = prevAtom()->asUnknownInset(); @@ -966,9 +1017,7 @@ InsetMathUnknown * Cursor::activeMacro() void Cursor::pullArg() { -#ifdef WITH_WARNINGS -#warning Look here -#endif + // FIXME: Look here MathData ar = cell(); if (popLeft() && inMathed()) { plainErase(); @@ -982,9 +1031,7 @@ void Cursor::pullArg() void Cursor::touch() { -#ifdef WITH_WARNINGS -#warning look here -#endif + // FIXME: look here #if 0 DocIterator::const_iterator it = begin(); DocIterator::const_iterator et = end(); @@ -1016,26 +1063,52 @@ void Cursor::normalize() } -bool Cursor::goUpDown(bool up) +bool Cursor::upDownInMath(bool up) { // Be warned: The 'logic' implemented in this function is highly // fragile. A distance of one pixel or a '<' vs '<=' _really // matters. So fiddle around with it only if you think you know // what you are doing! - int xo = 0; int yo = 0; getPos(xo, yo); + xo = beforeDispX_; // check if we had something else in mind, if not, this is the future // target - if (x_target() == -1) - x_target() = xo; - else - xo = x_target(); + if (x_target_ == -1) + setTargetX(xo); + else if (inset().asTextInset() && xo - textTargetOffset() != x_target()) { + // In text mode inside the line (not left or right) possibly set a new target_x, + // but only if we are somewhere else than the previous target-offset. + + // We want to keep the x-target on subsequent up/down movements + // that cross beyond the end of short lines. Thus a special + // handling when the cursor is at the end of line: Use the new + // x-target only if the old one was before the end of line + // or the old one was after the beginning of the line + bool inRTL = isWithinRtlParagraph(*this); + bool left; + bool right; + if (inRTL) { + left = pos() == textRow().endpos(); + right = pos() == textRow().pos(); + } else { + left = pos() == textRow().pos(); + right = pos() == textRow().endpos(); + } + if ((!left && !right) || + (left && !right && xo < x_target_) || + (!left && right && x_target_ < xo)) + setTargetX(xo); + else + xo = targetX(); + } else + xo = targetX(); // try neigbouring script insets - if (!selection()) { + Cursor old = *this; + if (inMathed() && !selection()) { // try left if (pos() != 0) { InsetMathScript const * p = prevAtom()->asScriptInset(); @@ -1044,10 +1117,19 @@ bool Cursor::goUpDown(bool up) push(*const_cast(p)); idx() = p->idxOfScript(up); pos() = lastpos(); - return true; + + // we went in the right direction? Otherwise don't jump into the script + int x; + int y; + getPos(x, y); + if ((!up && y <= beforeDispY_) || + (up && y >= beforeDispY_)) + operator=(old); + else + return true; } } - + // try right if (pos() != lastpos()) { InsetMathScript const * p = nextAtom()->asScriptInset(); @@ -1055,60 +1137,157 @@ bool Cursor::goUpDown(bool up) push(*const_cast(p)); idx() = p->idxOfScript(up); pos() = 0; - return true; + + // we went in the right direction? Otherwise don't jump into the script + int x; + int y; + getPos(x, y); + if ((!up && y <= beforeDispY_) || + (up && y >= beforeDispY_)) + operator=(old); + else + return true; } } } + + // try to find an inset that knows better then we, + if (inset().idxUpDown(*this, up)) { + //lyxerr << "idxUpDown triggered" << endl; + // try to find best position within this inset + if (!selection()) + setCursor(bruteFind2(*this, xo, yo)); + return true; + } + + // any improvement going just out of inset? + if (popLeft() && inMathed()) { + //lyxerr << "updown: popLeft succeeded" << endl; + int xnew; + int ynew; + getPos(xnew, ynew); + if (up ? ynew < beforeDispY_ : ynew > beforeDispY_) + return true; + } + + // no success, we are probably at the document top or bottom + operator=(old); + return false; +} -// FIXME: Switch this on for more robust movement -#if 0 - return bruteFind3(*this, xo, yo, up); - -#else - //xarray().boundingBox(xlow, xhigh, ylow, yhigh); - //if (up) - // yhigh = yo - 4; - //else - // ylow = yo + 4; - //if (bruteFind(*this, xo, yo, xlow, xhigh, ylow, yhigh)) { - // lyxerr << "updown: handled by brute find in the same cell" << endl; - // return true; - //} - - // try to find an inset that knows better then we - while (true) { - //lyxerr << "updown: We are in " << &inset() << " idx: " << idx() << endl; - // ask inset first - if (inset().idxUpDown(*this, up)) { - //lyxerr << "idxUpDown triggered" << endl; - // try to find best position within this inset - if (!selection()) - setCursor(bruteFind2(*this, xo, yo)); - return true; +bool Cursor::upDownInText(bool up, bool & updateNeeded) +{ + BOOST_ASSERT(text()); + + // where are we? + int xo = 0; + int yo = 0; + getPos(xo, yo); + xo = beforeDispX_; + + // update the targetX - this is here before the "return false" + // to set a new target which can be used by InsetTexts above + // if we cannot move up/down inside this inset anymore + if (x_target_ == -1) + setTargetX(xo); + else if (xo - textTargetOffset() != x_target() && + depth() == beforeDispatchCursor_.depth()) { + // In text mode inside the line (not left or right) possibly set a new target_x, + // but only if we are somewhere else than the previous target-offset. + + // We want to keep the x-target on subsequent up/down movements + // that cross beyond the end of short lines. Thus a special + // handling when the cursor is at the end of line: Use the new + // x-target only if the old one was before the end of line + // or the old one was after the beginning of the line + bool inRTL = isWithinRtlParagraph(*this); + bool left; + bool right; + if (inRTL) { + left = pos() == textRow().endpos(); + right = pos() == textRow().pos(); + } else { + left = pos() == textRow().pos(); + right = pos() == textRow().endpos(); } + if ((!left && !right) || + (left && !right && xo < x_target_) || + (!left && right && x_target_ < xo)) + setTargetX(xo); + else + xo = targetX(); + } else + xo = targetX(); + + // first get the current line + TextMetrics & tm = bv_->textMetrics(text()); + ParagraphMetrics const & pm = tm.parMetrics(pit()); + int row; + if (pos() && boundary()) + row = pm.pos2row(pos() - 1); + else + row = pm.pos2row(pos()); + + // are we not at the start or end? + if (up) { + if (pit() == 0 && row == 0) + return false; + } else { + if (pit() + 1 >= int(text()->paragraphs().size()) && + row + 1 >= int(pm.rows().size())) + return false; + } - // no such inset found, just take something "above" - if (!popLeft()) { - //lyxerr << "updown: popleft failed (strange case)" << endl; - int ylow = up ? 0 : yo + 1; - int yhigh = up ? yo - 1 : bv().workHeight(); - return bruteFind(*this, xo, yo, 0, bv().workWidth(), ylow, yhigh); + // with and without selection are handled differently + if (!selection()) { + int yo = bv().getPos(*this, boundary()).y_; + Cursor old = *this; + // To next/previous row + if (up) + tm.editXY(*this, xo, yo - textRow().ascent() - 1); + else + tm.editXY(*this, xo, yo + textRow().descent() + 1); + clearSelection(); + + // This happens when you move out of an inset. + // And to give the DEPM the possibility of doing + // something we must provide it with two different + // cursors. (Lgb) + Cursor dummy = *this; + if (dummy == old) + ++dummy.pos(); + if (bv().checkDepm(dummy, old)) { + updateNeeded = true; + // Make sure that cur gets back whatever happened to dummy(Lgb) + operator=(dummy); + } + } else { + // if there is a selection, we stay out of any inset, and just jump to the right position: + Cursor old = *this; + if (up) { + if (row > 0) { + top().pos() = std::min(tm.x2pos(pit(), row - 1, xo), top().lastpos()); + } else if (pit() > 0) { + --pit(); + ParagraphMetrics const & pmcur = bv_->parMetrics(text(), pit()); + top().pos() = std::min(tm.x2pos(pit(), pmcur.rows().size() - 1, xo), top().lastpos()); + } + } else { + if (row + 1 < int(pm.rows().size())) { + top().pos() = std::min(tm.x2pos(pit(), row + 1, xo), top().lastpos()); + } else if (pit() + 1 < int(text()->paragraphs().size())) { + ++pit(); + top().pos() = std::min(tm.x2pos(pit(), 0, xo), top().lastpos()); + } } - // any improvement so far? - //lyxerr << "updown: popLeft succeeded" << endl; - int xnew; - int ynew; - getPos(xnew, ynew); - if (up ? ynew < yo : ynew > yo) - return true; + updateNeeded |= bv().checkDepm(*this, old); } - // we should not come here. - BOOST_ASSERT(false); -#endif -} + updateTextTargetOffset(); + return true; +} void Cursor::handleFont(string const & font) @@ -1164,7 +1343,7 @@ docstring Cursor::selectionAsString(bool label) const return docstring(); if (inTexted()) { - Buffer const & buffer = *bv().buffer(); + Buffer const & buffer = bv().buffer(); ParagraphList const & pars = text()->paragraphs(); // should be const ... @@ -1178,12 +1357,14 @@ docstring Cursor::selectionAsString(bool label) const // First paragraph in selection docstring result = pars[startpit]. - asString(buffer, startpos, pars[startpit].size(), label) + "\n\n"; + asString(buffer, startpos, pars[startpit].size(), label) + + parbreak(pars[startpit]); // The paragraphs in between (if any) for (pit_type pit = startpit + 1; pit != endpit; ++pit) { Paragraph const & par = pars[pit]; - result += par.asString(buffer, 0, par.size(), label) + "\n\n"; + result += par.asString(buffer, 0, par.size(), label) + + parbreak(pars[pit]); } // Last paragraph in selection @@ -1224,8 +1405,6 @@ Encoding const * Cursor::getEncoding() const { if (empty()) return 0; - if (!bv().buffer()) - return 0; int s = 0; // go up until first non-0 text is hit // (innermost text is 0 in mathed) @@ -1233,9 +1412,9 @@ Encoding const * Cursor::getEncoding() const if (operator[](s).text()) break; CursorSlice const & sl = operator[](s); - LyXText const & text = *sl.text(); + Text const & text = *sl.text(); Font font = text.getPar(sl.pit()).getFont( - bv().buffer()->params(), sl.pos(), outerFont(sl.pit(), text.paragraphs())); + bv().buffer().params(), sl.pos(), outerFont(sl.pit(), text.paragraphs())); return font.language()->encoding(); } @@ -1266,70 +1445,190 @@ void Cursor::noUpdate() Font Cursor::getFont() const { + // The logic here should more or less match to the Cursor::setCurrentFont + // logic, i.e. the cursor height should give a hint what will happen + // if a character is entered. + // HACK. far from being perfect... - int s = 0; // go up until first non-0 text is hit // (innermost text is 0 in mathed) + int s = 0; for (s = depth() - 1; s >= 0; --s) if (operator[](s).text()) break; CursorSlice const & sl = operator[](s); - LyXText const & text = *sl.text(); - Font font = text.getPar(sl.pit()).getFont( - bv().buffer()->params(), - sl.pos(), + Text const & text = *sl.text(); + Paragraph const & par = text.getPar(sl.pit()); + + // on boundary, so we are really at the character before + pos_type pos = sl.pos(); + if (pos > 0 && boundary()) + --pos; + + // on space? Take the font before (only for RTL boundary stay) + if (pos > 0) { + TextMetrics const & tm = bv().textMetrics(&text); + if (pos == sl.lastpos() + || (par.isSeparator(pos) + && !tm.isRTLBoundary(sl.pit(), pos))) + --pos; + } + + // get font at the position + Font font = par.getFont(bv().buffer().params(), pos, outerFont(sl.pit(), text.paragraphs())); return font; } -void Cursor::fixIfBroken() +bool Cursor::fixIfBroken() { - // find out last good level - Cursor copy = *this; - size_t newdepth = depth(); - while (!copy.empty()) { - if (copy.idx() > copy.lastidx()) { - lyxerr << "wrong idx " << copy.idx() - << ", max is " << copy.lastidx() - << " at level " << copy.depth() - << ". Trying to correct this." << endl; - lyxerr << "old: " << *this << endl; - newdepth = copy.depth() - 1; - } - else if (copy.pit() > copy.lastpit()) { - lyxerr << "wrong pit " << copy.pit() - << ", max is " << copy.lastpit() - << " at level " << copy.depth() - << ". Trying to correct this." << endl; - lyxerr << "old: " << *this << endl; - newdepth = copy.depth() - 1; - } - else if (copy.pos() > copy.lastpos()) { - lyxerr << "wrong pos " << copy.pos() - << ", max is " << copy.lastpos() - << " at level " << copy.depth() - << ". Trying to correct this." << endl; - lyxerr << "old: " << *this << endl; - newdepth = copy.depth() - 1; + if (DocIterator::fixIfBroken()) { + clearSelection(); + resetAnchor(); + return true; + } + return false; +} + + +bool notifyCursorLeaves(DocIterator const & old, Cursor & cur) +{ + // find inset in common + size_type i; + for (i = 0; i < old.depth() && i < cur.depth(); ++i) { + if (&old.inset() != &cur.inset()) + break; + } + + // notify everything on top of the common part in old cursor, + // but stop if the inset claims the cursor to be invalid now + for (; i < old.depth(); ++i) { + if (old[i].inset().notifyCursorLeaves(cur)) + return true; + } + + return false; +} + + +void Cursor::setCurrentFont() +{ + CursorSlice const & cs = innerTextSlice(); + Paragraph const & par = cs.paragraph(); + pos_type cpit = cs.pit(); + pos_type cpos = cs.pos(); + Text const & ctext = *cs.text(); + TextMetrics const & tm = bv().textMetrics(&ctext); + + // are we behind previous char in fact? -> go to that char + if (cpos > 0 && boundary()) + --cpos; + + // find position to take the font from + if (cpos != 0) { + // paragraph end? -> font of last char + if (cpos == lastpos()) + --cpos; + // on space? -> look at the words in front of space + else if (cpos > 0 && par.isSeparator(cpos)) { + // abc| def -> font of c + // abc |[WERBEH], i.e. boundary==true -> font of c + // abc [WERBEH]| def, font of the space + if (!tm.isRTLBoundary(cpit, cpos)) + --cpos; } - copy.pop(); } - // shrink cursor to a size where everything is valid, possibly - // leaving insets - while (depth() > newdepth) { - pop(); - lyxerr << "correcting cursor to level " << depth() << endl; - lyxerr << "new: " << *this << endl; - clearSelection(); + + // get font + BufferParams const & bufparams = buffer().params(); + current_font = par.getFontSettings(bufparams, cpos); + real_current_font = tm.getDisplayFont(cpit, cpos); + + // special case for paragraph end + if (cs.pos() == lastpos() + && tm.isRTLBoundary(cpit, cs.pos()) + && !boundary()) { + Language const * lang = par.getParLanguage(bufparams); + current_font.setLanguage(lang); + current_font.fontInfo().setNumber(FONT_OFF); + real_current_font.setLanguage(lang); + real_current_font.fontInfo().setNumber(FONT_OFF); } } -bool Cursor::isRTL() const +bool Cursor::textUndo() +{ + DocIterator dit = *this; + // Undo::textUndo() will modify dit. + if (!bv_->buffer().undo().textUndo(dit)) + return false; + // Set cursor + setCursor(dit); + selection() = false; + resetAnchor(); + fixIfBroken(); + return true; +} + + +bool Cursor::textRedo() +{ + DocIterator dit = *this; + // Undo::textRedo() will modify dit. + if (!bv_->buffer().undo().textRedo(dit)) + return false; + // Set cursor + setCursor(dit); + selection() = false; + resetAnchor(); + fixIfBroken(); + return true; +} + + +void Cursor::finishUndo() +{ + bv_->buffer().undo().finishUndo(); +} + + +void Cursor::recordUndo(UndoKind kind, pit_type from, pit_type to) +{ + bv_->buffer().undo().recordUndo(*this, kind, from, to); +} + + +void Cursor::recordUndo(UndoKind kind, pit_type from) +{ + bv_->buffer().undo().recordUndo(*this, kind, from); +} + + +void Cursor::recordUndo(UndoKind kind) +{ + bv_->buffer().undo().recordUndo(*this, kind); +} + + +void Cursor::recordUndoInset(UndoKind kind) +{ + bv_->buffer().undo().recordUndoInset(*this, kind); +} + + +void Cursor::recordUndoFullDocument() +{ + bv_->buffer().undo().recordUndoFullDocument(*this); +} + + +void Cursor::recordUndoSelection() { - return top().paragraph().isRightToLeftPar(bv().buffer()->params()); + bv_->buffer().undo().recordUndo(*this, ATOMIC_UNDO, + selBegin().pit(), selEnd().pit()); }