]> git.lyx.org Git - features.git/blobdiff - src/text2.C
Introducing a number of tags parametrizing various
[features.git] / src / text2.C
index 3f6bd33901f29f79dbba0d38e6c011ef68364b1c..73d96266eecdc224a1e5295d5fa2298f1ef3b7e9 100644 (file)
 #include "BufferView.h"
 #include "Bullet.h"
 #include "counters.h"
+#include "cursor.h"
 #include "CutAndPaste.h"
 #include "debug.h"
+#include "dispatchresult.h"
 #include "errorlist.h"
 #include "Floating.h"
 #include "FloatList.h"
@@ -68,13 +70,12 @@ using std::ostringstream;
 using std::string;
 
 
-LyXText::LyXText(BufferView * bv, InsetText * inset, bool ininset,
+LyXText::LyXText(BufferView * bv, InsetText * inset, bool in_inset,
          ParagraphList & paragraphs)
-       : height(0), width(0), anchor_y_(0),
-         inset_owner(inset), the_locking_inset(0), bv_owner(bv),
-         in_inset_(ininset), paragraphs_(&paragraphs)
-{
-}
+       : height(0), width(0), textwidth_(bv ? bv->workWidth() : 100),
+         inset_owner(inset), bv_owner(bv),
+         in_inset_(in_inset), paragraphs_(&paragraphs), xo_(0), yo_(0)
+{}
 
 
 void LyXText::init(BufferView * bview)
@@ -89,8 +90,6 @@ void LyXText::init(BufferView * bview)
        width = 0;
        height = 0;
 
-       anchor_y_ = 0;
-
        current_font = getFont(beg, 0);
 
        redoParagraphs(beg, end);
@@ -113,47 +112,37 @@ LyXFont LyXText::getFont(ParagraphList::iterator pit, pos_type pos) const
        LyXLayout_ptr const & layout = pit->layout();
 #warning broken?
        BufferParams const & params = bv()->buffer()->params();
+       pos_type const body_pos = pit->beginOfBody();
 
        // We specialize the 95% common case:
        if (!pit->getDepth()) {
-               if (layout->labeltype == LABEL_MANUAL
-                   && pos < pit->beginningOfBody()) {
-                       // 1% goes here
-                       LyXFont f = pit->getFontSettings(params, pos);
-                       if (pit->inInset())
-                               pit->inInset()->getDrawFont(f);
+               LyXFont f = pit->getFontSettings(params, pos);
+               if (pit->inInset())
+                       pit->inInset()->getDrawFont(f);
+               if (layout->labeltype == LABEL_MANUAL && pos < body_pos)
                        return f.realize(layout->reslabelfont);
-               } else {
-                       LyXFont f = pit->getFontSettings(params, pos);
-                       if (pit->inInset())
-                               pit->inInset()->getDrawFont(f);
+               else
                        return f.realize(layout->resfont);
-               }
        }
 
        // The uncommon case need not be optimized as much
-
        LyXFont layoutfont;
-
-       if (pos < pit->beginningOfBody()) {
-               // 1% goes here
+       if (pos < body_pos)
                layoutfont = layout->labelfont;
-       } else {
-               // 99% goes here
+       else
                layoutfont = layout->font;
-       }
 
-       LyXFont tmpfont = pit->getFontSettings(params, pos);
-       tmpfont.realize(layoutfont);
+       LyXFont font = pit->getFontSettings(params, pos);
+       font.realize(layoutfont);
 
        if (pit->inInset())
-               pit->inInset()->getDrawFont(tmpfont);
+               pit->inInset()->getDrawFont(font);
 
        // Realize with the fonts of lesser depth.
-       tmpfont.realize(outerFont(pit, ownerParagraphs()));
-       tmpfont.realize(defaultfont_);
+       //font.realize(outerFont(pit, ownerParagraphs()));
+       font.realize(defaultfont_);
 
-       return tmpfont;
+       return font;
 }
 
 
@@ -166,7 +155,7 @@ LyXFont LyXText::getLayoutFont(ParagraphList::iterator pit) const
 
        LyXFont font = layout->font;
        // Realize with the fonts of lesser depth.
-       font.realize(outerFont(pit, ownerParagraphs()));
+       //font.realize(outerFont(pit, ownerParagraphs()));
        font.realize(defaultfont_);
 
        return font;
@@ -219,7 +208,7 @@ void LyXText::setCharFont(
        // Get concrete layout font to reduce against
        LyXFont layoutfont;
 
-       if (pos < pit->beginningOfBody())
+       if (pos < pit->beginOfBody())
                layoutfont = layout->labelfont;
        else
                layoutfont = layout->font;
@@ -265,9 +254,10 @@ void LyXText::toggleInset()
                // No, try to see if we are inside a collapsable inset
                if (inset_owner && inset_owner->owner()
                    && inset_owner->owner()->isOpen()) {
-                       bv()->unlockInset(inset_owner->owner());
-                       inset_owner->owner()->close(bv());
-                       bv()->getLyXText()->cursorRight(bv());
+                       finishUndo();
+                       inset_owner->owner()->close();
+                       bv()->getLyXText()->cursorRight(true);
+                       bv()->updateParagraphDialog();
                }
                return;
        }
@@ -278,15 +268,13 @@ void LyXText::toggleInset()
                recUndo(cursor.par());
 
        if (inset->isOpen())
-               inset->close(bv());
+               inset->close();
        else
-               inset->open(bv());
-
-       bv()->updateInset(inset);
+               inset->open();
 }
 
 
-/* used in setlayout */
+// used in setLayout
 // Asger is not sure we want to do this...
 void LyXText::makeFontEntriesLayoutSpecific(BufferParams const & params,
                                            Paragraph & par)
@@ -296,7 +284,7 @@ void LyXText::makeFontEntriesLayoutSpecific(BufferParams const & params,
 
        LyXFont layoutfont;
        for (pos_type pos = 0; pos < psize; ++pos) {
-               if (pos < par.beginningOfBody())
+               if (pos < par.beginOfBody())
                        layoutfont = layout->labelfont;
                else
                        layoutfont = layout->font;
@@ -408,7 +396,7 @@ void LyXText::setLayout(string const & layout)
 bool LyXText::changeDepth(bv_funcs::DEPTH_CHANGE type, bool test_only)
 {
        ParagraphList::iterator pit = cursorPar();
-       ParagraphList::iterator end = cursorPar();
+       ParagraphList::iterator end = pit;
        ParagraphList::iterator start = pit;
 
        if (selection.set()) {
@@ -417,8 +405,6 @@ bool LyXText::changeDepth(bv_funcs::DEPTH_CHANGE type, bool test_only)
                start = pit;
        }
 
-       ParagraphList::iterator pastend = boost::next(end);
-
        if (!test_only)
                recUndo(parOffset(start), parOffset(end));
 
@@ -447,6 +433,7 @@ bool LyXText::changeDepth(bv_funcs::DEPTH_CHANGE type, bool test_only)
 
                prev_after_depth = pit->getMaxDepthAfter();
 
+#warning SERIOUS: Uahh... does this mean we access end->getMaxDepthAfter?
                if (pit == end) {
                        break;
                }
@@ -457,7 +444,7 @@ bool LyXText::changeDepth(bv_funcs::DEPTH_CHANGE type, bool test_only)
        if (test_only)
                return changed;
 
-       redoParagraphs(start, pastend);
+       redoParagraphs(start, boost::next(end));
 
        // We need to actually move the text->cursor. I don't
        // understand why ...
@@ -489,7 +476,7 @@ void LyXText::setFont(LyXFont const & font, bool toggleall)
        if (!selection.set()) {
                // Determine basis font
                LyXFont layoutfont;
-               if (cursor.pos() < cursorPar()->beginningOfBody()) {
+               if (cursor.pos() < cursorPar()->beginOfBody()) {
                        layoutfont = getLabelFont(cursorPar());
                } else {
                        layoutfont = getLayoutFont(cursorPar());
@@ -549,7 +536,6 @@ void LyXText::setFont(LyXFont const & font, bool toggleall)
 
 // the cursor set functions have a special mechanism. When they
 // realize, that you left an empty paragraph, they will delete it.
-// They also delete the corresponding row
 
 // need the selection cursor:
 void LyXText::setSelection()
@@ -558,26 +544,30 @@ void LyXText::setSelection()
 }
 
 
-
 void LyXText::clearSelection()
 {
        TextCursor::clearSelection();
 
-       // reset this in the bv_owner!
-       if (bv_owner && bv_owner->text)
-               bv_owner->text->xsel_cache.set(false);
+       // reset this in the bv()!
+       if (bv() && bv()->text)
+               bv()->text->xsel_cache.set(false);
 }
 
 
 void LyXText::cursorHome()
 {
-       setCursor(cursorPar(), cursorRow()->pos());
+       ParagraphList::iterator cpit = cursorPar();
+       setCursor(cpit, cpit->getRow(cursor.pos())->pos());
 }
 
 
 void LyXText::cursorEnd()
 {
-       setCursor(cursorPar(), cursorRow()->end() - 1);
+       ParagraphList::iterator cpit = cursorPar();
+       pos_type end = cpit->getRow(cursor.pos())->endpos();
+       // if not on the last row of the par, put the cursor before
+       // the final space
+       setCursor(cpit, end == cpit->size() ? end : end - 1);
 }
 
 
@@ -600,7 +590,8 @@ void LyXText::toggleFree(LyXFont const & font, bool toggleall)
        // If the mask is completely neutral, tell user
        if (font == LyXFont(LyXFont::ALL_IGNORE)) {
                // Could only happen with user style
-               bv()->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
+               bv()->owner()->message(_("No font change defined. "
+                       "Use Character under the Layout menu to define font change."));
                return;
        }
 
@@ -608,9 +599,10 @@ void LyXText::toggleFree(LyXFont const & font, bool toggleall)
        // If there is a change in the language the implicit word selection
        // is disabled.
        LyXCursor resetCursor = cursor;
-       bool implicitSelection = (font.language() == ignore_language
-                                 && font.number() == LyXFont::IGNORE)
-               ? selectWordWhenUnderCursor(lyx::WHOLE_WORD_STRICT) : false;
+       bool implicitSelection =
+               font.language() == ignore_language
+               && font.number() == LyXFont::IGNORE
+               && selectWordWhenUnderCursor(lyx::WHOLE_WORD_STRICT);
 
        // Set font
        setFont(font, toggleall);
@@ -659,11 +651,10 @@ string LyXText::getStringToIndex()
 // the DTP switches for paragraphs. LyX will store them in the first
 // physical paragraph. When a paragraph is broken, the top settings rest,
 // the bottom settings are given to the new one. So I can make sure,
-// they do not duplicate themself and you cannnot make dirty things with
+// they do not duplicate themself and you cannot play dirty tricks with
 // them!
 
-void LyXText::setParagraph(bool line_top, bool line_bottom,
-                          bool pagebreak_top, bool pagebreak_bottom,
+void LyXText::setParagraph(
                           VSpace const & space_top,
                           VSpace const & space_bottom,
                           Spacing const & spacing,
@@ -694,7 +685,6 @@ void LyXText::setParagraph(bool line_top, bool line_bottom,
 
        recUndo(selection.start.par(), parOffset(undoendpit) - 1);
 
-
        int tmppit = selection.end.par();
 
        while (tmppit != selection.start.par() - 1) {
@@ -702,14 +692,10 @@ void LyXText::setParagraph(bool line_top, bool line_bottom,
 
                ParagraphList::iterator const pit = cursorPar();
                ParagraphParameters & params = pit->params();
-
-               params.lineTop(line_top);
-               params.lineBottom(line_bottom);
-               params.pagebreakTop(pagebreak_top);
-               params.pagebreakBottom(pagebreak_bottom);
                params.spaceTop(space_top);
                params.spaceBottom(space_bottom);
                params.spacing(spacing);
+
                // does the layout allow the new alignment?
                LyXLayout_ptr const & layout = pit->layout();
 
@@ -734,13 +720,10 @@ void LyXText::setParagraph(bool line_top, bool line_bottom,
        setCursor(selection.end.par(), selection.end.pos());
        setSelection();
        setCursor(tmpcursor.par(), tmpcursor.pos());
-       if (inset_owner)
-               bv()->updateInset(inset_owner);
+       bv()->update();
 }
 
 
-namespace {
-
 string expandLabel(LyXTextClass const & textclass,
        LyXLayout_ptr const & layout, bool appendix)
 {
@@ -763,13 +746,14 @@ string expandLabel(LyXTextClass const & textclass,
 }
 
 
+namespace {
+
 void incrementItemDepth(ParagraphList::iterator pit,
                        ParagraphList::iterator first_pit)
 {
        int const cur_labeltype = pit->layout()->labeltype;
 
-       if (cur_labeltype != LABEL_ENUMERATE &&
-           cur_labeltype != LABEL_ITEMIZE)
+       if (cur_labeltype != LABEL_ENUMERATE && cur_labeltype != LABEL_ITEMIZE)
                return;
 
        int const cur_depth = pit->getDepth();
@@ -996,7 +980,9 @@ void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit)
 }
 
 
-// Updates all counters. Paragraphs with changed label string will be rebroken
+// Updates all counters. Paragraphs with changed label string will be
+// not be rebroken as this is too expensive. The next round will get it
+// right anyway...
 void LyXText::updateCounters()
 {
        // start over
@@ -1005,8 +991,6 @@ void LyXText::updateCounters()
        ParagraphList::iterator beg = ownerParagraphs().begin();
        ParagraphList::iterator end = ownerParagraphs().end();
        for (ParagraphList::iterator pit = beg; pit != end; ++pit) {
-               string const oldLabel = pit->params().labelString();
-
                size_t maxdepth = 0;
                if (pit != beg)
                        maxdepth = boost::prior(pit)->getMaxDepthAfter();
@@ -1016,11 +1000,6 @@ void LyXText::updateCounters()
 
                // setCounter can potentially change the labelString.
                setCounter(*bv()->buffer(), pit);
-
-               string const & newLabel = pit->params().labelString();
-
-               if (oldLabel != newLabel)
-                       redoParagraph(pit);
        }
 }
 
@@ -1029,6 +1008,7 @@ void LyXText::insertInset(InsetOld * inset)
 {
        if (!cursorPar()->insetAllowed(inset->lyxCode()))
                return;
+
        recUndo(cursor.par());
        freezeUndo();
        cursorPar()->insertInset(cursor.pos(), inset);
@@ -1036,11 +1016,12 @@ void LyXText::insertInset(InsetOld * inset)
        // The character will not be inserted a second time
        insertChar(Paragraph::META_INSET);
        // If we enter a highly editable inset the cursor should be before
-       // the inset. After an Undo LyX tries to call inset->edit(...)
+       // the inset. After an undo LyX tries to call inset->edit(...)
        // and fails if the cursor is behind the inset and getInset
        // does not return the inset!
        if (isHighlyEditableInset(inset))
                cursorLeft(true);
+
        unFreezeUndo();
 }
 
@@ -1184,7 +1165,7 @@ void LyXText::setSelectionRange(lyx::pos_type length)
 
        selection.cursor = cursor;
        while (length--)
-               cursorRight(bv());
+               cursorRight(true);
        setSelection();
 }
 
@@ -1308,7 +1289,8 @@ void LyXText::setCursor(LyXCursor & cur, paroffset_type par,
        // get the cursor y position in text
 
        ParagraphList::iterator pit = getPar(par);
-       Row const & row = *getRow(*pit, pos);
+       Row const & row = *pit->getRow(pos);
+
        int y = pit->y + row.y_offset();
 
        // y is now the beginning of the cursor row
@@ -1316,33 +1298,44 @@ void LyXText::setCursor(LyXCursor & cur, paroffset_type par,
        // y is now the cursor baseline
        cur.y(y);
 
-       pos_type last = lastPos(*pit, row);
+       pos_type const end = row.endpos();
 
        // None of these should happen, but we're scaredy-cats
-       if (pos > pit->size()) {
-               lyxerr << "dont like 1, pos: " << pos << " size: " << pit->size() << endl;
+       if (pos < 0) {
+               lyxerr << "dont like -1" << endl;
                pos = 0;
                cur.pos(0);
-       } else if (pos > last + 1) {
+               BOOST_ASSERT(false);
+       } else if (pos > pit->size()) {
+               lyxerr << "dont like 1, pos: " << pos
+                      << " size: " << pit->size()
+                      << " row.pos():" << row.pos()
+                      << " paroffset: " << par << endl;
+               pos = 0;
+               cur.pos(0);
+               BOOST_ASSERT(false);
+       } else if (pos > end) {
                lyxerr << "dont like 2 please report" << endl;
                // This shouldn't happen.
-               pos = last + 1;
+               pos = end;
                cur.pos(pos);
+               BOOST_ASSERT(false);
        } else if (pos < row.pos()) {
-               lyxerr << "dont like 3 please report" << endl;
+               lyxerr << "dont like 3 please report pos:" << pos
+                      << " size: " << pit->size()
+                      << " row.pos():" << row.pos()
+                      << " paroffset: " << par << endl;
                pos = row.pos();
                cur.pos(pos);
+               BOOST_ASSERT(false);
        }
-
        // now get the cursors x position
-       float x = getCursorX(pit, row, pos, last, boundary);
-       cur.x(int(x));
-       cur.x_fix(cur.x());
+       cur.x(int(getCursorX(pit, row, pos, boundary)));
 }
 
 
 float LyXText::getCursorX(ParagraphList::iterator pit, Row const & row,
-                         pos_type pos, pos_type last, bool boundary) const
+                         pos_type pos, bool boundary) const
 {
        pos_type cursor_vpos    = 0;
        double x                = row.x();
@@ -1350,32 +1343,33 @@ float LyXText::getCursorX(ParagraphList::iterator pit, Row const & row,
        double fill_hfill       = row.fill_hfill();
        double fill_label_hfill = row.fill_label_hfill();
        pos_type const row_pos  = row.pos();
+       pos_type const end = row.endpos();
 
-       if (last < row_pos)
+       if (end <= row_pos)
                cursor_vpos = row_pos;
-       else if (pos > last && !boundary)
+       else if (pos >= end && !boundary)
                cursor_vpos = (pit->isRightToLeftPar(bv()->buffer()->params()))
-                       ? row_pos : last + 1;
-       else if (pos > row_pos && (pos > last || boundary))
+                       ? row_pos : end;
+       else if (pos > row_pos && (pos >= end || boundary))
                // Place cursor after char at (logical) position pos - 1
-               cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
-                       ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
+               cursor_vpos = (bidi.level(pos - 1) % 2 == 0)
+                       ? bidi.log2vis(pos - 1) + 1 : bidi.log2vis(pos - 1);
        else
                // Place cursor before char at (logical) position pos
-               cursor_vpos = (bidi_level(pos) % 2 == 0)
-                       ? log2vis(pos) : log2vis(pos) + 1;
+               cursor_vpos = (bidi.level(pos) % 2 == 0)
+                       ? bidi.log2vis(pos) : bidi.log2vis(pos) + 1;
 
-       pos_type body_pos = pit->beginningOfBody();
+       pos_type body_pos = pit->beginOfBody();
        if (body_pos > 0 &&
-           (body_pos - 1 > last || !pit->isLineSeparator(body_pos - 1)))
+           (body_pos > end || !pit->isLineSeparator(body_pos - 1)))
                body_pos = 0;
 
        for (pos_type vpos = row_pos; vpos < cursor_vpos; ++vpos) {
-               pos_type pos = vis2log(vpos);
+               pos_type pos = bidi.vis2log(vpos);
                if (body_pos > 0 && pos == body_pos - 1) {
-                       x += fill_label_hfill +
-                               font_metrics::width(
-                                       pit->layout()->labelsep, getLabelFont(pit));
+                       x += fill_label_hfill
+                               + font_metrics::width(pit->layout()->labelsep,
+                                                     getLabelFont(pit));
                        if (pit->isLineSeparator(body_pos - 1))
                                x -= singleWidth(pit, body_pos - 1);
                }
@@ -1401,6 +1395,7 @@ void LyXText::setCursorIntern(paroffset_type par,
                              pos_type pos, bool setfont, bool boundary)
 {
        setCursor(cursor, par, pos, boundary);
+       bv()->x_target(cursor.x() + xo_);
        if (setfont)
                setCurrentFont();
 }
@@ -1419,9 +1414,9 @@ void LyXText::setCurrentFont()
                        --pos;
                else // potentional bug... BUG (Lgb)
                        if (pit->isSeparator(pos)) {
-                               if (pos > cursorRow()->pos() &&
-                                   bidi_level(pos) % 2 ==
-                                   bidi_level(pos - 1) % 2)
+                               if (pos > pit->getRow(pos)->pos() &&
+                                   bidi.level(pos) % 2 ==
+                                   bidi.level(pos - 1) % 2)
                                        --pos;
                                else if (pos + 1 < pit->size())
                                        ++pos;
@@ -1433,7 +1428,7 @@ void LyXText::setCurrentFont()
        real_current_font = getFont(pit, pos);
 
        if (cursor.pos() == pit->size() &&
-           isBoundary(*bv()->buffer(), *pit, cursor.pos()) &&
+           bidi.isBoundary(*bv()->buffer(), *pit, cursor.pos()) &&
            !cursor.boundary()) {
                Language const * lang =
                        pit->getParLanguage(bufparams);
@@ -1456,28 +1451,28 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
        double fill_label_hfill = row.fill_label_hfill();
 
        pos_type vc = row.pos();
-       pos_type last = lastPos(*pit, row);
+       pos_type end = row.endpos();
        pos_type c = 0;
        LyXLayout_ptr const & layout = pit->layout();
 
        bool left_side = false;
 
-       pos_type body_pos = pit->beginningOfBody();
+       pos_type body_pos = pit->beginOfBody();
        double last_tmpx = tmpx;
 
        if (body_pos > 0 &&
-           (body_pos - 1 > last ||
+           (body_pos > end ||
             !pit->isLineSeparator(body_pos - 1)))
                body_pos = 0;
 
        // check for empty row
-       if (!pit->size()) {
+       if (vc == end) {
                x = int(tmpx);
                return 0;
        }
 
-       while (vc <= last && tmpx <= x) {
-               c = vis2log(vc);
+       while (vc < end && tmpx <= x) {
+               c = bidi.vis2log(vc);
                last_tmpx = tmpx;
                if (body_pos > 0 && c == body_pos - 1) {
                        tmpx += fill_label_hfill +
@@ -1507,13 +1502,12 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
                left_side = true;
        }
 
-       if (vc > last + 1)  // This shouldn't happen.
-               vc = last + 1;
+       BOOST_ASSERT(vc <= end);  // This shouldn't happen.
 
        boundary = false;
        // This (rtl_support test) is not needed, but gives
        // some speedup if rtl_support == false
-       bool const lastrow = lyxrc.rtl_support && row.end() == pit->size();
+       bool const lastrow = lyxrc.rtl_support && row.endpos() == pit->size();
 
        // If lastrow is false, we don't need to compute
        // the value of rtl.
@@ -1522,27 +1516,27 @@ pos_type LyXText::getColumnNearX(ParagraphList::iterator pit,
                : false;
        if (lastrow &&
                 ((rtl  &&  left_side && vc == row.pos() && x < tmpx - 5) ||
-                 (!rtl && !left_side && vc == last + 1   && x > tmpx + 5)))
-               c = last + 1;
+                 (!rtl && !left_side && vc == end  && x > tmpx + 5)))
+               c = end;
        else if (vc == row.pos()) {
-               c = vis2log(vc);
-               if (bidi_level(c) % 2 == 1)
+               c = bidi.vis2log(vc);
+               if (bidi.level(c) % 2 == 1)
                        ++c;
        } else {
-               c = vis2log(vc - 1);
-               bool const rtl = (bidi_level(c) % 2 == 1);
+               c = bidi.vis2log(vc - 1);
+               bool const rtl = (bidi.level(c) % 2 == 1);
                if (left_side == rtl) {
                        ++c;
-                       boundary = isBoundary(*bv()->buffer(), *pit, c);
+                       boundary = bidi.isBoundary(*bv()->buffer(), *pit, c);
                }
        }
 
-       if (row.pos() <= last && c > last && pit->isNewline(last)) {
-               if (bidi_level(last) % 2 == 0)
-                       tmpx -= singleWidth(pit, last);
+       if (row.pos() < end && c >= end && pit->isNewline(end - 1)) {
+               if (bidi.level(end -1) % 2 == 0)
+                       tmpx -= singleWidth(pit, end - 1);
                else
-                       tmpx += singleWidth(pit, last);
-               c = last;
+                       tmpx += singleWidth(pit, end - 1);
+               c = end - 1;
        }
 
        c -= row.pos();
@@ -1559,7 +1553,7 @@ void LyXText::setCursorFromCoordinates(int x, int y)
        deleteEmptyParagraphMechanism(old_cursor);
 }
 
-
+// x,y are coordinates relative to this LyXText
 void LyXText::setCursorFromCoordinates(LyXCursor & cur, int x, int y)
 {
        // Get the row first.
@@ -1578,107 +1572,181 @@ void LyXText::setCursorFromCoordinates(LyXCursor & cur, int x, int y)
 }
 
 
-void LyXText::cursorLeft(bool internal)
+bool LyXText::checkAndActivateInset(bool front)
+{
+       if (cursor.pos() == cursorPar()->size())
+               return false;
+       InsetOld * inset = cursorPar()->getInset(cursor.pos());
+       if (!isHighlyEditableInset(inset))
+               return false;
+       inset->edit(bv(), front);
+       return true;
+}
+
+
+DispatchResult LyXText::moveRight()
+{
+       if (cursorPar()->isRightToLeftPar(bv()->buffer()->params()))
+               return moveLeftIntern(false, true, false);
+       else
+               return moveRightIntern(true, true, false);
+}
+
+
+DispatchResult LyXText::moveLeft()
+{
+       if (cursorPar()->isRightToLeftPar(bv()->buffer()->params()))
+               return moveRightIntern(true, true, false);
+       else
+               return moveLeftIntern(false, true, false);
+}
+
+
+DispatchResult LyXText::moveRightIntern(bool front, bool activate_inset, bool selecting)
+{
+       ParagraphList::iterator c_par = cursorPar();
+       if (boost::next(c_par) == ownerParagraphs().end()
+               && cursor.pos() >= c_par->size())
+               return DispatchResult(false, FINISHED_RIGHT);
+       if (activate_inset && checkAndActivateInset(front))
+               return DispatchResult(true, true);
+       cursorRight(true);
+       if (!selecting)
+               clearSelection();
+       return DispatchResult(true);
+}
+
+
+DispatchResult LyXText::moveLeftIntern(bool front,
+                         bool activate_inset, bool selecting)
+{
+       if (cursor.par() == 0 && cursor.pos() <= 0)
+               return DispatchResult(false, FINISHED);
+       cursorLeft(true);
+       if (!selecting)
+               clearSelection();
+       if (activate_inset && checkAndActivateInset(front))
+               return DispatchResult(true, true);
+       return DispatchResult(true);
+}
+
+
+DispatchResult LyXText::moveUp()
+{
+       if (cursorPar() == firstPar() && cursorRow() == firstRow())
+               return DispatchResult(false, FINISHED_UP);
+       cursorUp(false);
+       clearSelection();
+       return DispatchResult(true);
+}
+
+
+DispatchResult LyXText::moveDown()
+{
+       if (cursorPar() == lastPar() && cursorRow() == lastRow())
+               return DispatchResult(false, FINISHED_DOWN);
+       cursorDown(false);
+       clearSelection();
+       return DispatchResult(true);
+}
+
+
+bool LyXText::cursorLeft(bool internal)
 {
        if (cursor.pos() > 0) {
                bool boundary = cursor.boundary();
                setCursor(cursor.par(), cursor.pos() - 1, true, false);
                if (!internal && !boundary &&
-                   isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos() + 1))
+                   bidi.isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos() + 1))
                        setCursor(cursor.par(), cursor.pos() + 1, true, true);
-       } else if (cursor.par() != 0) {
+               return true;
+       }
+
+       if (cursor.par() != 0) {
                // steps into the paragraph above
                setCursor(cursor.par() - 1, boost::prior(cursorPar())->size());
+               return true;
        }
+
+       return false;
 }
 
 
-void LyXText::cursorRight(bool internal)
+bool LyXText::cursorRight(bool internal)
 {
-       bool const at_end = (cursor.pos() == cursorPar()->size());
-       bool const at_newline = !at_end &&
-               cursorPar()->isNewline(cursor.pos());
-
-       if (!internal && cursor.boundary() && !at_newline)
+       if (!internal && cursor.boundary()) {
                setCursor(cursor.par(), cursor.pos(), true, false);
-       else if (!at_end) {
+               return true;
+       }
+
+       if (cursor.pos() != cursorPar()->size()) {
                setCursor(cursor.par(), cursor.pos() + 1, true, false);
-               if (!internal &&
-                   isBoundary(*bv()->buffer(), *cursorPar(), cursor.pos()))
+               if (!internal && bidi.isBoundary(*bv()->buffer(), *cursorPar(),
+                                                cursor.pos()))
                        setCursor(cursor.par(), cursor.pos(), true, true);
-       } else if (cursor.par() + 1 != int(ownerParagraphs().size()))
+               return true;
+       }
+
+       if (cursor.par() + 1 != int(ownerParagraphs().size())) {
                setCursor(cursor.par() + 1, 0);
+               return true;
+       }
+
+       return false;
 }
 
 
 void LyXText::cursorUp(bool selecting)
 {
-#if 1
-       int x = cursor.x_fix();
-       int y = cursor.y() - cursorRow()->baseline() - 1;
+       Row const & row = *cursorRow();
+       int x = bv()->x_target() - xo_;
+       int y = cursor.y() - row.baseline() - 1;
        setCursorFromCoordinates(x, y);
+
        if (!selecting) {
-               int topy = bv_owner->top_y();
-               int y1 = cursor.y() - topy;
-               int y2 = y1;
-               y -= topy;
-               InsetOld * inset_hit = checkInsetHit(x, y1);
-               if (inset_hit && isHighlyEditableInset(inset_hit)) {
-                       inset_hit->localDispatch(
-                               FuncRequest(bv(), LFUN_INSET_EDIT, x, y - (y2 - y1), mouse_button::none));
-               }
+               int y_abs = y + yo_ - bv()->top_y();
+               InsetOld * inset_hit = checkInsetHit(bv()->x_target(), y_abs);
+               if (inset_hit && isHighlyEditableInset(inset_hit))
+                       inset_hit->edit(bv(), bv()->x_target(), y_abs);
        }
-#else
-       lyxerr << "cursorUp: y " << cursor.y() << " bl: " <<
-               cursorRow()->baseline() << endl;
-       setCursorFromCoordinates(cursor.x_fix(),
-               cursor.y() - cursorRow()->baseline() - 1);
-#endif
 }
 
 
 void LyXText::cursorDown(bool selecting)
 {
-#if 1
-       int x = cursor.x_fix();
-       int y = cursor.y() - cursorRow()->baseline() + cursorRow()->height() + 1;
+       Row const & row = *cursorRow();
+       int x = bv()->x_target() - xo_;
+       int y = cursor.y() - row.baseline() + row.height() + 1;
        setCursorFromCoordinates(x, y);
+
        if (!selecting) {
-               int topy = bv_owner->top_y();
-               int y1 = cursor.y() - topy;
-               int y2 = y1;
-               y -= topy;
-               InsetOld * inset_hit = checkInsetHit(x, y1);
-               if (inset_hit && isHighlyEditableInset(inset_hit)) {
-                       FuncRequest cmd(bv(), LFUN_INSET_EDIT, x, y - (y2 - y1), mouse_button::none);
-                       inset_hit->localDispatch(cmd);
-               }
+               int y_abs = y + yo_ - bv()->top_y();
+               InsetOld * inset_hit = checkInsetHit(bv()->x_target(), y_abs);
+               if (inset_hit && isHighlyEditableInset(inset_hit))
+                       inset_hit->edit(bv(), bv()->x_target(), y_abs);
        }
-#else
-       setCursorFromCoordinates(cursor.x_fix(),
-                cursor.y() - cursorRow()->baseline() + cursorRow()->height() + 1);
-#endif
 }
 
 
 void LyXText::cursorUpParagraph()
 {
+       ParagraphList::iterator cpit = cursorPar();
        if (cursor.pos() > 0)
-               setCursor(cursorPar(), 0);
-       else if (cursorPar() != ownerParagraphs().begin())
-               setCursor(boost::prior(cursorPar()), 0);
+               setCursor(cpit, 0);
+       else if (cpit != ownerParagraphs().begin())
+               setCursor(boost::prior(cpit), 0);
 }
 
 
 void LyXText::cursorDownParagraph()
 {
-       ParagraphList::iterator par = cursorPar();
-       ParagraphList::iterator next_par = boost::next(par);
+       ParagraphList::iterator pit = cursorPar();
+       ParagraphList::iterator next_pit = boost::next(pit);
 
-       if (next_par != ownerParagraphs().end())
-               setCursor(next_par, 0);
+       if (next_pit != ownerParagraphs().end())
+               setCursor(next_pit, 0);
        else
-               setCursor(par, par->size());
+               setCursor(pit, pit->size());
 }
 
 
@@ -1789,8 +1857,8 @@ bool LyXText::deleteEmptyParagraphMechanism(LyXCursor const & old_cursor)
        // we can't possibly have deleted a paragraph before this point
        bool deleted = false;
 
-       if (old_pit->empty() ||
-           (old_pit->size() == 1 && old_pit->isLineSeparator(0))) {
+       if (old_pit->empty()
+           || (old_pit->size() == 1 && old_pit->isLineSeparator(0))) {
                // ok, we will delete something
                LyXCursor tmpcursor;
 
@@ -1810,8 +1878,12 @@ bool LyXText::deleteEmptyParagraphMechanism(LyXCursor const & old_cursor)
                recUndo(parOffset(old_pit), parOffset(endpit) - 1);
                cursor = tmpcursor;
 
+               // cache cursor pit
+               ParagraphList::iterator tmppit = cursorPar();
                // delete old par
                ownerParagraphs().erase(old_pit);
+               // update cursor par offset
+               cursor.par(parOffset(tmppit));
                redoParagraph();
 
                // correct cursor y
@@ -1822,15 +1894,17 @@ bool LyXText::deleteEmptyParagraphMechanism(LyXCursor const & old_cursor)
                        selection.cursor = cursor;
                }
        }
-       if (!deleted) {
-               if (old_pit->stripLeadingSpaces()) {
-                       redoParagraph(old_pit);
-                       // correct cursor y
-                       setCursorIntern(cursor.par(), cursor.pos());
-                       selection.cursor = cursor;
-               }
+
+       if (deleted)
+               return true;
+
+       if (old_pit->stripLeadingSpaces()) {
+               redoParagraph(old_pit);
+               // correct cursor y
+               setCursorIntern(cursor.par(), cursor.pos());
+               selection.cursor = cursor;
        }
-       return deleted;
+       return false;
 }
 
 
@@ -1862,6 +1936,5 @@ bool LyXText::isInInset() const
 int defaultRowHeight()
 {
        LyXFont const font(LyXFont::ALL_SANE);
-       return int(font_metrics::maxAscent(font)
-                + font_metrics::maxDescent(font) * 1.5);
+       return int(font_metrics::maxHeight(font) *  1.2);
 }