]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Change the interface to a paragraph's layout. We still store a LayoutPtr, but now...
[lyx.git] / src / TextMetrics.cpp
index 360b3c772abf703f4075d20557e219641bd591fc..385c023a86dba0d7c9fc23e7899051b6d20612c8 100644 (file)
@@ -27,7 +27,6 @@
 #include "CoordCache.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
-#include "support/debug.h"
 #include "FontIterator.h"
 #include "FuncRequest.h"
 #include "InsetList.h"
@@ -49,6 +48,8 @@
 #include "frontends/FontMetrics.h"
 #include "frontends/Painter.h"
 
+#include "support/debug.h"
+
 using namespace std;
 
 namespace lyx {
@@ -127,7 +128,7 @@ TextMetrics::TextMetrics(BufferView * bv, Text * text)
 }
 
 
-bool TextMetrics::has(pit_type pit) const
+bool TextMetrics::contains(pit_type pit) const
 {
        return par_metrics_.find(pit) != par_metrics_.end();
 }
@@ -220,13 +221,13 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width)
 
 int TextMetrics::rightMargin(ParagraphMetrics const & pm) const
 {
-       return main_text_? pm.rightMargin(bv_->buffer()) : 0;
+       return main_text_? pm.rightMargin(*bv_) : 0;
 }
 
 
 int TextMetrics::rightMargin(pit_type const pit) const
 {
-       return main_text_? par_metrics_[pit].rightMargin(bv_->buffer()) : 0;
+       return main_text_? par_metrics_[pit].rightMargin(*bv_) : 0;
 }
 
 
@@ -240,13 +241,13 @@ void TextMetrics::applyOuterFont(Font & font) const
 }
 
 
-Font TextMetrics::getDisplayFont(pit_type pit, pos_type pos) const
+Font TextMetrics::displayFont(pit_type pit, pos_type pos) const
 {
        BOOST_ASSERT(pos >= 0);
 
        ParagraphList const & pars = text_->paragraphs();
        Paragraph const & par = pars[pit];
-       LayoutPtr const & layout = par.layout();
+       Layout const & layout = par.layout();
        Buffer const & buffer = bv_->buffer();
        // FIXME: broken?
        BufferParams const & params = buffer.params();
@@ -257,10 +258,10 @@ Font TextMetrics::getDisplayFont(pit_type pit, pos_type pos) const
                Font f = par.getFontSettings(params, pos);
                if (!text_->isMainText(buffer))
                        applyOuterFont(f);
-               bool lab = layout->labeltype == LABEL_MANUAL && pos < body_pos;
+               bool lab = layout.labeltype == LABEL_MANUAL && pos < body_pos;
 
-               FontInfo const & lf = lab ? layout->labelfont : layout->font;
-               FontInfo rlf = lab ? layout->reslabelfont : layout->resfont;
+               FontInfo const & lf = lab ? layout.labelfont : layout.font;
+               FontInfo rlf = lab ? layout.reslabelfont : layout.resfont;
                
                // In case the default family has been customized
                if (lf.family() == INHERIT_FAMILY)
@@ -271,7 +272,7 @@ Font TextMetrics::getDisplayFont(pit_type pit, pos_type pos) const
 
        // The uncommon case need not be optimized as much
        FontInfo const & layoutfont = pos < body_pos ? 
-               layout->labelfont : layout->font;
+               layout.labelfont : layout.font;
 
        Font font = par.getFontSettings(params, pos);
        font.fontInfo().realize(layoutfont);
@@ -301,7 +302,7 @@ bool TextMetrics::isRTL(CursorSlice const & sl, bool boundary) const
        if (boundary && sl.pos() > 0)
                correction = -1;
                
-       return getDisplayFont(sl.pit(), sl.pos() + correction).isVisibleRightToLeft();
+       return displayFont(sl.pit(), sl.pos() + correction).isVisibleRightToLeft();
 }
 
 
@@ -316,12 +317,12 @@ bool TextMetrics::isRTLBoundary(pit_type pit, pos_type pos) const
 
        Paragraph const & par = text_->getPar(pit);
 
-       bool left = getDisplayFont(pit, pos - 1).isVisibleRightToLeft();
+       bool left = displayFont(pit, pos - 1).isVisibleRightToLeft();
        bool right;
        if (pos == par.size())
                right = par.isRTL(bv_->buffer().params());
        else
-               right = getDisplayFont(pit, pos).isVisibleRightToLeft();
+               right = displayFont(pit, pos).isVisibleRightToLeft();
        return left != right;
 }
 
@@ -338,7 +339,7 @@ bool TextMetrics::isRTLBoundary(pit_type pit, pos_type pos,
        if (pos == par.size())
                right = par.isRTL(bv_->buffer().params());
        else
-               right = getDisplayFont(pit, pos).isVisibleRightToLeft();
+               right = displayFont(pit, pos).isVisibleRightToLeft();
        return left != right;
 }
 
@@ -356,13 +357,13 @@ bool TextMetrics::redoParagraph(pit_type const pit)
        main_text_ = (text_ == &buffer.text());
        bool changed = false;
 
-       // FIXME This check ought to be done somewhere else. It is the reason
+       // FIXME: This check ought to be done somewhere else. It is the reason
        // why text_ is not     const. But then, where else to do it?
        // Well, how can you end up with either (a) a biblio environment that
        // has no InsetBibitem or (b) a biblio environment with more than one
        // InsetBibitem? I think the answer is: when paragraphs are merged;
        // when layout is set; when material is pasted.
-       int const moveCursor = par.checkBiblio(buffer.params().trackChanges);
+       int const moveCursor = par.checkBiblio(buffer);
        if (moveCursor > 0)
                const_cast<Cursor &>(bv_->cursor()).posForward();
        else if (moveCursor < 0) {
@@ -379,7 +380,16 @@ bool TextMetrics::redoParagraph(pit_type const pit)
        DocIterator parPos = text_->macrocontextPosition();
        if (!parPos.empty())
                parPos.pit() = pit;
-
+       else {
+               LYXERR(Debug::INFO, "MacroContext not initialised!"
+                       << " Going through the buffer again and hope"
+                       << " the context is better then.");
+               updateLabels(bv_->buffer());
+               parPos = text_->macrocontextPosition();
+               BOOST_ASSERT(!parPos.empty());
+               parPos.pit() = pit;
+       }
+       
        // redo insets
        // FIXME: We should always use getFont(), see documentation of
        // noFontChange() in Inset.h.
@@ -404,7 +414,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                int const w = max_width_ - leftMargin(max_width_, pit, ii->pos)
                        - right_margin;
                Font const & font = ii->inset->noFontChange() ?
-                       bufferfont : getDisplayFont(pit, ii->pos);
+                       bufferfont : displayFont(pit, ii->pos);
                MacroContext mc(buffer, parPos);
                MetricsInfo mi(bv_, font.fontInfo(), w, mc);
                ii->inset->metrics(mi, dim);
@@ -413,28 +423,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                changed |= (old_dim != dim);
        }
 
-       Cursor const & cur = bv_->cursor();
-       DocIterator sel_beg = cur.selectionBegin();
-       DocIterator sel_end = cur.selectionEnd();
-       bool selection = cur.selection()
-               // This is out text.
-               && cur.text() == text_
-               // if the anchor is outside, this is not our selection 
-               && cur.anchor().text() == text_
-               && pit >= sel_beg.pit() && pit <= sel_end.pit();
-
-       // We care only about visible selection.
-       if (selection) {
-               if (pit != sel_beg.pit()) {
-                       sel_beg.pit() = pit;
-                       sel_beg.pos() = 0;
-               }
-               if (pit != sel_end.pit()) {
-                       sel_end.pit() = pit;
-                       sel_end.pos() = sel_end.lastpos();
-               }
-       }
-
        par.setBeginOfBody();
        pos_type first = 0;
        size_t row_index = 0;
@@ -457,10 +445,6 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                row.setChanged(false);
                row.pos(first);
                row.endpos(end);
-               if (selection)
-                       row.setSelection(sel_beg.pos(), sel_end.pos());
-               else
-                       row.setSelection(-1, -1);
                row.setDimension(dim);
                int const max_row_width = max(dim_.wid, dim.wid);
                computeRowMetrics(pit, row, max_row_width);
@@ -524,10 +508,10 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                row.x = leftMargin(max_width_, pit, row.pos());
 
        // is there a manual margin with a manual label
-       LayoutPtr const & layout = par.layout();
+       Layout const & layout = par.layout();
 
-       if (layout->margintype == MARGIN_MANUAL
-           && layout->labeltype == LABEL_MANUAL) {
+       if (layout.margintype == MARGIN_MANUAL
+           && layout.labeltype == LABEL_MANUAL) {
                /// We might have real hfills in the label part
                int nlh = numberOfLabelHfills(par, row);
 
@@ -556,16 +540,13 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                // set x how you need it
                int align;
                if (par.params().align() == LYX_ALIGN_LAYOUT)
-                       align = layout->align;
+                       align = layout.align;
                else
                        align = par.params().align();
 
                // Display-style insets should always be on a centred row
-               // The test on par.size() is to catch zero-size pars, which
-               // would trigger the assert in Paragraph::getInset().
-               //inset = par.size() ? par.getInset(row.pos()) : 0;
-               if (row.pos() < par.size() && par.isInset(row.pos())) {
-                       switch(par.getInset(row.pos())->display()) {
+               if (Inset const * inset = par.getInset(row.pos())) {
+                       switch (inset->display()) {
                                case Inset::AlignLeft:
                                        align = LYX_ALIGN_BLOCK;
                                        break;
@@ -620,8 +601,8 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                if (body_pos > 0
                    && (body_pos > end || !par.isLineSeparator(body_pos - 1)))
                {
-                       row.x += theFontMetrics(text_->getLabelFont(buffer, par)).
-                               width(layout->labelsep);
+                       row.x += theFontMetrics(text_->labelFont(buffer, par)).
+                               width(layout.labelsep);
                        if (body_pos <= end)
                                row.x += row.label_hfill;
                }
@@ -677,7 +658,7 @@ int TextMetrics::labelFill(pit_type const pit, Row const & row) const
                return 0;
 
        FontMetrics const & fm
-               = theFontMetrics(text_->getLabelFont(buffer, par));
+               = theFontMetrics(text_->labelFont(buffer, par));
 
        return max(0, fm.width(label) - w);
 }
@@ -699,7 +680,7 @@ static pos_type addressBreakPoint(pos_type i, Paragraph const & par)
 int TextMetrics::labelEnd(pit_type const pit) const
 {
        // labelEnd is only needed if the layout fills a flushleft label.
-       if (text_->getPar(pit).layout()->margintype != MARGIN_MANUAL)
+       if (text_->getPar(pit).layout().margintype != MARGIN_MANUAL)
                return 0;
        // return the beginning of the body
        return leftMargin(max_width_, pit);
@@ -716,13 +697,22 @@ pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
        if (pos == end || width < 0)
                return end;
 
-       LayoutPtr const & layout = par.layout();
+       Layout const & layout = par.layout();
 
-       if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX)
+       if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX)
                return addressBreakPoint(pos, par);
 
        pos_type const body_pos = par.beginOfBody();
 
+       // check for possible inline completion
+       DocIterator const & inlineCompletionPos = bv_->inlineCompletionPos();
+       pos_type inlineCompletionLPos = -1;
+       if (inlineCompletionPos.inTexted()
+           && inlineCompletionPos.text() == text_
+           && inlineCompletionPos.pit() == pit) {
+               // draw logically behind the previous character
+               inlineCompletionLPos = inlineCompletionPos.pos() - 1;
+       }
 
        // Now we iterate through until we reach the right margin
        // or the end of the par, then choose the possible break
@@ -741,11 +731,18 @@ pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
        for ( ; i < end; ++i, ++fi) {
                int thiswidth = pm.singleWidth(i, *fi);
 
+               // add inline completion width
+               if (inlineCompletionLPos == i) {
+                       docstring const & completion = bv_->inlineCompletion();
+                       if (completion.length() > 0)
+                               thiswidth += theFontMetrics(*fi).width(completion);
+               }
+
                // add the auto-hfill from label end to the body
                if (body_pos && i == body_pos) {
                        FontMetrics const & fm = theFontMetrics(
-                               text_->getLabelFont(buffer, par));
-                       int add = fm.width(layout->labelsep);
+                               text_->labelFont(buffer, par));
+                       int add = fm.width(layout.labelsep);
                        if (par.isLineSeparator(i - 1))
                                add -= singleWidth(pit, i - 1);
 
@@ -774,20 +771,22 @@ pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
                        point = i + 1;
                        break;
                }
+               Inset const * inset = 0;
                // Break before...
                if (i + 1 < end) {
-                       if (par.isInset(i + 1) && par.getInset(i + 1)->display()) {
+                       if ((inset = par.getInset(i + 1)) && inset->display()) {
                                point = i + 1;
                                break;
                        }
                        // ...and after.
-                       if (par.isInset(i) && par.getInset(i)->display()) {
+                       if ((inset = par.getInset(i)) && inset->display()) {
                                point = i + 1;
                                break;
                        }
                }
 
-               if (!par.isInset(i) || par.getInset(i)->isChar()) {
+               inset = par.getInset(i);
+               if (!inset || inset->isChar()) {
                        // some insets are line separators too
                        if (par.isLineSeparator(i)) {
                                // register breakpoint:
@@ -821,6 +820,16 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
        int w = leftMargin(max_width_, pit, first);
        int label_end = labelEnd(pit);
 
+       // check for possible inline completion
+       DocIterator const & inlineCompletionPos = bv_->inlineCompletionPos();
+       pos_type inlineCompletionLPos = -1;
+       if (inlineCompletionPos.inTexted()
+           && inlineCompletionPos.text() == text_
+           && inlineCompletionPos.pit() == pit) {
+               // draw logically behind the previous character
+               inlineCompletionLPos = inlineCompletionPos.pos() - 1;
+       }
+
        pos_type const body_pos = par.beginOfBody();
        pos_type i = first;
 
@@ -829,20 +838,27 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
                for ( ; i < end; ++i, ++fi) {
                        if (body_pos > 0 && i == body_pos) {
                                FontMetrics const & fm = theFontMetrics(
-                                       text_->getLabelFont(buffer, par));
-                               w += fm.width(par.layout()->labelsep);
+                                       text_->labelFont(buffer, par));
+                               w += fm.width(par.layout().labelsep);
                                if (par.isLineSeparator(i - 1))
                                        w -= singleWidth(pit, i - 1);
                                w = max(w, label_end);
                        }
                        w += pm.singleWidth(i, *fi);
+
+                       // add inline completion width
+                       if (inlineCompletionLPos == i) {
+                               docstring const & completion = bv_->inlineCompletion();
+                               if (completion.length() > 0)
+                                       w += theFontMetrics(*fi).width(completion);
+                       }
                }
        }
 
        if (body_pos > 0 && body_pos >= end) {
                FontMetrics const & fm = theFontMetrics(
-                       text_->getLabelFont(buffer, par));
-               w += fm.width(par.layout()->labelsep);
+                       text_->labelFont(buffer, par));
+               w += fm.width(par.layout().labelsep);
                if (end > 0 && par.isLineSeparator(end - 1))
                        w -= singleWidth(pit, end - 1);
                w = max(w, label_end);
@@ -853,7 +869,7 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
 
 
 Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
-               pos_type const end) const
+               pos_type const end, bool topBottomSpace) const
 {
        Paragraph const & par = text_->getPar(pit);
        // get the maximum ascent and the maximum descent
@@ -864,26 +880,26 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
        // ok, let us initialize the maxasc and maxdesc value.
        // Only the fontsize count. The other properties
        // are taken from the layoutfont. Nicer on the screen :)
-       LayoutPtr const & layout = par.layout();
+       Layout const & layout = par.layout();
 
        // as max get the first character of this row then it can
        // increase but not decrease the height. Just some point to
        // start with so we don't have to do the assignment below too
        // often.
        Buffer const & buffer = bv_->buffer();
-       Font font = getDisplayFont(pit, first);
+       Font font = displayFont(pit, first);
        FontSize const tmpsize = font.fontInfo().size();
-       font.fontInfo() = text_->getLayoutFont(buffer, pit);
+       font.fontInfo() = text_->layoutFont(buffer, pit);
        FontSize const size = font.fontInfo().size();
        font.fontInfo().setSize(tmpsize);
 
-       FontInfo labelfont = text_->getLabelFont(buffer, par);
+       FontInfo labelfont = text_->labelFont(buffer, par);
 
        FontMetrics const & labelfont_metrics = theFontMetrics(labelfont);
        FontMetrics const & fontmetrics = theFontMetrics(font);
 
        // these are minimum values
-       double const spacing_val = layout->spacing.getValue()
+       double const spacing_val = layout.spacing.getValue()
                * text_->spacing(buffer, par);
        //lyxerr << "spacing_val = " << spacing_val << endl;
        int maxasc  = int(fontmetrics.maxAscent()  * spacing_val);
@@ -924,7 +940,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
        ParagraphList const & pars = text_->paragraphs();
 
        // is it a top line?
-       if (first == 0) {
+       if (first == 0 && topBottomSpace) {
                BufferParams const & bufparams = buffer.params();
                // some parskips VERY EASY IMPLEMENTATION
                if (bufparams.paragraph_separation
@@ -932,8 +948,8 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                        && par.ownerCode() != ERT_CODE
                        && par.ownerCode() != LISTINGS_CODE
                        && pit > 0
-                       && ((layout->isParagraph() && par.getDepth() == 0)
-                           || (pars[pit - 1].layout()->isParagraph()
+                       && ((layout.isParagraph() && par.getDepth() == 0)
+                           || (pars[pit - 1].layout().isParagraph()
                                && pars[pit - 1].getDepth() == 0)))
                {
                                maxasc += bufparams.getDefSkip().inPixels(*bv_);
@@ -944,25 +960,25 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
 
                // This is special code for the chapter, since the label of this
                // layout is printed in an extra row
-               if (layout->counter == "chapter"
+               if (layout.counter == "chapter"
                    && !par.params().labelString().empty()) {
                        labeladdon = int(labelfont_metrics.maxHeight()
-                                    * layout->spacing.getValue()
+                                    * layout.spacing.getValue()
                                     * text_->spacing(buffer, par));
                }
 
                // special code for the top label
-               if ((layout->labeltype == LABEL_TOP_ENVIRONMENT
-                    || layout->labeltype == LABEL_BIBLIO
-                    || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
+               if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
+                    || layout.labeltype == LABEL_BIBLIO
+                    || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
                    && isFirstInSequence(pit, pars)
-                   && !par.getLabelstring().empty())
+                   && !par.labelString().empty())
                {
                        labeladdon = int(
                                  labelfont_metrics.maxHeight()
-                                       * layout->spacing.getValue()
+                                       * layout.spacing.getValue()
                                        * text_->spacing(buffer, par)
-                               + (layout->topsep + layout->labelbottomsep) * dh);
+                               + (layout.topsep + layout.labelbottomsep) * dh);
                }
 
                // Add the layout spaces, for example before and after
@@ -976,26 +992,26 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                    && prevpar.getDepth() == par.getDepth()
                    && prevpar.getLabelWidthString()
                                        == par.getLabelWidthString()) {
-                       layoutasc = layout->itemsep * dh;
+                       layoutasc = layout.itemsep * dh;
                } else if (pit != 0 || first != 0) {
-                       if (layout->topsep > 0)
-                               layoutasc = layout->topsep * dh;
+                       if (layout.topsep > 0)
+                               layoutasc = layout.topsep * dh;
                }
 
                prev = outerHook(pit, pars);
                if (prev != pit_type(pars.size())) {
-                       maxasc += int(pars[prev].layout()->parsep * dh);
+                       maxasc += int(pars[prev].layout().parsep * dh);
                } else if (pit != 0) {
                        Paragraph const & prevpar = pars[pit - 1];
                        if (prevpar.getDepth() != 0 ||
                                        prevpar.layout() == layout) {
-                               maxasc += int(layout->parsep * dh);
+                               maxasc += int(layout.parsep * dh);
                        }
                }
        }
 
        // is it a bottom line?
-       if (end >= par.size()) {
+       if (end >= par.size() && topBottomSpace) {
                // add the layout spaces, for example before and after
                // a section, or between the items of a itemize or enumerate
                // environment
@@ -1006,18 +1022,18 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                        double unusual = 0;
 
                        if (pars[cpit].getDepth() > pars[nextpit].getDepth()) {
-                               usual = pars[cpit].layout()->bottomsep * dh;
+                               usual = pars[cpit].layout().bottomsep * dh;
                                cpit = depthHook(cpit, pars, pars[nextpit].getDepth());
                                if (pars[cpit].layout() != pars[nextpit].layout()
                                        || pars[nextpit].getLabelWidthString() != pars[cpit].getLabelWidthString())
                                {
-                                       unusual = pars[cpit].layout()->bottomsep * dh;
+                                       unusual = pars[cpit].layout().bottomsep * dh;
                                }
                                layoutdesc = max(unusual, usual);
                        } else if (pars[cpit].getDepth() == pars[nextpit].getDepth()) {
                                if (pars[cpit].layout() != pars[nextpit].layout()
                                        || pars[nextpit].getLabelWidthString() != pars[cpit].getLabelWidthString())
-                                       layoutdesc = int(pars[cpit].layout()->bottomsep * dh);
+                                       layoutdesc = int(pars[cpit].layout().bottomsep * dh);
                        }
                }
        }
@@ -1030,7 +1046,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
        // following code in another method specially tailored for the
        // main Text. The following test is thus bogus.
        // Top and bottom margin of the document (only at top-level)
-       if (main_text_) {
+       if (main_text_ && topBottomSpace) {
                if (pit == 0 && first == 0)
                        maxasc += 20;
                if (pit + 1 == pit_type(pars.size()) &&
@@ -1063,7 +1079,7 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
        pos_type vc = row.pos();
        pos_type end = row.endpos();
        pos_type c = 0;
-       LayoutPtr const & layout = par.layout();
+       Layout const & layout = par.layout();
 
        bool left_side = false;
 
@@ -1087,8 +1103,8 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
                last_tmpx = tmpx;
                if (body_pos > 0 && c == body_pos - 1) {
                        FontMetrics const & fm = theFontMetrics(
-                               text_->getLabelFont(buffer, par));
-                       tmpx += row.label_hfill + fm.width(layout->labelsep);
+                               text_->labelFont(buffer, par));
+                       tmpx += row.label_hfill + fm.width(layout.labelsep);
                        if (par.isLineSeparator(body_pos - 1))
                                tmpx -= singleWidth(pit, body_pos - 1);
                }
@@ -1116,9 +1132,10 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
        bool const rtl = lastrow ? text_->isRTL(buffer, par) : false;
        if (lastrow &&
            ((rtl  &&  left_side && vc == row.pos() && x < tmpx - 5) ||
-            (!rtl && !left_side && vc == end  && x > tmpx + 5)))
-               c = end;
-       else if (vc == row.pos()) {
+            (!rtl && !left_side && vc == end  && x > tmpx + 5))) {
+               if (!par.isNewline(end - 1))
+                       c = end;
+       } else if (vc == row.pos()) {
                c = bidi.vis2log(vc);
                if (bidi.level(c) % 2 == 1)
                        ++c;
@@ -1483,6 +1500,18 @@ int TextMetrics::cursorX(CursorSlice const & sl,
            (body_pos > end || !par.isLineSeparator(body_pos - 1)))
                body_pos = 0;
 
+       // check for possible inline completion in this row
+       DocIterator const & inlineCompletionPos = bv_->inlineCompletionPos();
+       pos_type inlineCompletionVPos = -1;
+       if (inlineCompletionPos.inTexted()
+           && inlineCompletionPos.text() == text_
+           && inlineCompletionPos.pit() == pit
+           && inlineCompletionPos.pos() - 1 >= row_pos
+           && inlineCompletionPos.pos() - 1 < end) {
+               // draw logically behind the previous character
+               inlineCompletionVPos = bidi.log2vis(inlineCompletionPos.pos() - 1);
+       }
+
        // Use font span to speed things up, see below
        FontSpan font_span;
        Font font;
@@ -1492,6 +1521,15 @@ int TextMetrics::cursorX(CursorSlice const & sl,
        if (end > 0 && end < par.size() && par.isSeparator(end - 1))
                skipped_sep_vpos = bidi.log2vis(end - 1);
        
+       // Inline completion RTL special case row_pos == cursor_pos:
+       // "__|b" => cursor_pos is right of __
+       if (row_pos == inlineCompletionVPos && row_pos == cursor_vpos) {
+               font = displayFont(pit, row_pos + 1);
+               docstring const & completion = bv_->inlineCompletion();
+               if (font.isRightToLeft() && completion.length() > 0)
+                       x += theFontMetrics(font.fontInfo()).width(completion);
+       }
+       
        for (pos_type vpos = row_pos; vpos < cursor_vpos; ++vpos) {
                // Skip the separator which is at the logical end of the row
                if (vpos == skipped_sep_vpos)
@@ -1499,8 +1537,8 @@ int TextMetrics::cursorX(CursorSlice const & sl,
                pos_type pos = bidi.vis2log(vpos);
                if (body_pos > 0 && pos == body_pos - 1) {
                        FontMetrics const & labelfm = theFontMetrics(
-                               text_->getLabelFont(buffer, par));
-                       x += row.label_hfill + labelfm.width(par.layout()->labelsep);
+                               text_->labelFont(buffer, par));
+                       x += row.label_hfill + labelfm.width(par.layout().labelsep);
                        if (par.isLineSeparator(body_pos - 1))
                                x -= singleWidth(pit, body_pos - 1);
                }
@@ -1508,11 +1546,31 @@ int TextMetrics::cursorX(CursorSlice const & sl,
                // Use font span to speed things up, see above
                if (pos < font_span.first || pos > font_span.last) {
                        font_span = par.fontSpan(pos);
-                       font = getDisplayFont(pit, pos);
+                       font = displayFont(pit, pos);
                }
 
                x += pm.singleWidth(pos, font);
 
+               // Inline completion RTL case:
+               // "a__|b", __ of b => non-boundary a-pos is right of __
+               if (vpos + 1 == inlineCompletionVPos 
+                   && (vpos + 1 < cursor_vpos || !boundary_correction)) {
+                       font = displayFont(pit, vpos + 1);
+                       docstring const & completion = bv_->inlineCompletion();
+                       if (font.isRightToLeft() && completion.length() > 0)
+                               x += theFontMetrics(font.fontInfo()).width(completion);
+               }
+               
+               //  Inline completion LTR case:
+               // "b|__a", __ of b => non-boundary a-pos is in front of __
+               if (vpos == inlineCompletionVPos
+                   && (vpos + 1 < cursor_vpos || boundary_correction)) {
+                       font = displayFont(pit, vpos);
+                       docstring const & completion = bv_->inlineCompletion();
+                       if (!font.isRightToLeft() && completion.length() > 0)
+                               x += theFontMetrics(font.fontInfo()).width(completion);
+               }
+               
                if (par.isSeparator(pos) && pos >= body_pos)
                        x += row.separator;
        }
@@ -1552,45 +1610,6 @@ int TextMetrics::cursorY(CursorSlice const & sl, bool boundary) const
 }
 
 
-void TextMetrics::cursorPrevious(Cursor & cur)
-{
-       pos_type cpos = cur.pos();
-       pit_type cpar = cur.pit();
-
-       int x = cur.x_target();
-       setCursorFromCoordinates(cur, x, 0);
-       cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
-
-       if (cpar == cur.pit() && cpos == cur.pos())
-               // we have a row which is taller than the workarea. The
-               // simplest solution is to move to the previous row instead.
-               cur.dispatch(FuncRequest(cur.selection()? LFUN_UP_SELECT: LFUN_UP));
-
-       cur.finishUndo();
-       cur.updateFlags(Update::Force | Update::FitCursor);
-}
-
-
-void TextMetrics::cursorNext(Cursor & cur)
-{
-       pos_type cpos = cur.pos();
-       pit_type cpar = cur.pit();
-
-       int x = cur.x_target();
-       setCursorFromCoordinates(cur, x, cur.bv().workHeight() - 1);
-       cur.dispatch(FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
-
-       if (cpar == cur.pit() && cpos == cur.pos())
-               // we have a row which is taller than the workarea. The
-               // simplest solution is to move to the next row instead.
-               cur.dispatch(
-                       FuncRequest(cur.selection()? LFUN_DOWN_SELECT: LFUN_DOWN));
-
-       cur.finishUndo();
-       cur.updateFlags(Update::Force | Update::FitCursor);
-}
-
-
 // the cursor set functions have a special mechanism. When they
 // realize you left an empty paragraph, they will delete it.
 
@@ -1680,15 +1699,15 @@ int TextMetrics::leftMargin(int max_width,
        BOOST_ASSERT(pos <= par.size());
        Buffer const & buffer = bv_->buffer();
        //lyxerr << "TextMetrics::leftMargin: pit: " << pit << " pos: " << pos << endl;
-       TextClass const & tclass = buffer.params().getTextClass();
-       LayoutPtr const & layout = par.layout();
+       DocumentClass const & tclass = buffer.params().documentClass();
+       Layout const & layout = par.layout();
 
-       docstring parindent = layout->parindent;
+       docstring parindent = layout.parindent;
 
        int l_margin = 0;
 
        if (text_->isMainText(buffer))
-               l_margin += changebarMargin();
+               l_margin += bv_->leftMargin();
 
        l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
                tclass.leftmargin());
@@ -1697,14 +1716,15 @@ int TextMetrics::leftMargin(int max_width,
                // find the next level paragraph
                pit_type newpar = outerHook(pit, pars);
                if (newpar != pit_type(pars.size())) {
-                       if (pars[newpar].layout()->isEnvironment()) {
+                       if (pars[newpar].layout().isEnvironment()) {
                                l_margin = leftMargin(max_width, newpar);
                        }
-                       if (par.layout() == tclass.defaultLayout()) {
+                       if (tclass.isDefaultLayout(par.layout()) 
+                           || tclass.isEmptyLayout(par.layout())) {
                                if (pars[newpar].params().noindent())
                                        parindent.erase();
                                else
-                                       parindent = pars[newpar].layout()->parindent;
+                                       parindent = pars[newpar].layout().parindent;
                        }
                }
        }
@@ -1712,34 +1732,34 @@ int TextMetrics::leftMargin(int max_width,
        // This happens after sections in standard classes. The 1.3.x
        // code compared depths too, but it does not seem necessary
        // (JMarc)
-       if (par.layout() == tclass.defaultLayout()
-           && pit > 0 && pars[pit - 1].layout()->nextnoindent)
+       if (tclass.isDefaultLayout(par.layout())
+           && pit > 0 && pars[pit - 1].layout().nextnoindent)
                parindent.erase();
 
-       FontInfo const labelfont = text_->getLabelFont(buffer, par);
+       FontInfo const labelfont = text_->labelFont(buffer, par);
        FontMetrics const & labelfont_metrics = theFontMetrics(labelfont);
 
-       switch (layout->margintype) {
+       switch (layout.margintype) {
        case MARGIN_DYNAMIC:
-               if (!layout->leftmargin.empty()) {
+               if (!layout.leftmargin.empty()) {
                        l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
-                               layout->leftmargin);
+                               layout.leftmargin);
                }
-               if (!par.getLabelstring().empty()) {
-                       l_margin += labelfont_metrics.signedWidth(layout->labelindent);
-                       l_margin += labelfont_metrics.width(par.getLabelstring());
-                       l_margin += labelfont_metrics.width(layout->labelsep);
+               if (!par.labelString().empty()) {
+                       l_margin += labelfont_metrics.signedWidth(layout.labelindent);
+                       l_margin += labelfont_metrics.width(par.labelString());
+                       l_margin += labelfont_metrics.width(layout.labelsep);
                }
                break;
 
        case MARGIN_MANUAL: {
-               l_margin += labelfont_metrics.signedWidth(layout->labelindent);
+               l_margin += labelfont_metrics.signedWidth(layout.labelindent);
                // The width of an empty par, even with manual label, should be 0
                if (!par.empty() && pos >= par.beginOfBody()) {
                        if (!par.getLabelWidthString().empty()) {
                                docstring labstr = par.getLabelWidthString();
                                l_margin += labelfont_metrics.width(labstr);
-                               l_margin += labelfont_metrics.width(layout->labelsep);
+                               l_margin += labelfont_metrics.width(layout.labelsep);
                        }
                }
                break;
@@ -1747,31 +1767,31 @@ int TextMetrics::leftMargin(int max_width,
 
        case MARGIN_STATIC: {
                l_margin += theFontMetrics(buffer.params().getFont()).
-                       signedWidth(layout->leftmargin) * 4     / (par.getDepth() + 4);
+                       signedWidth(layout.leftmargin) * 4      / (par.getDepth() + 4);
                break;
        }
 
        case MARGIN_FIRST_DYNAMIC:
-               if (layout->labeltype == LABEL_MANUAL) {
+               if (layout.labeltype == LABEL_MANUAL) {
                        if (pos >= par.beginOfBody()) {
-                               l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
+                               l_margin += labelfont_metrics.signedWidth(layout.leftmargin);
                        } else {
-                               l_margin += labelfont_metrics.signedWidth(layout->labelindent);
+                               l_margin += labelfont_metrics.signedWidth(layout.labelindent);
                        }
                } else if (pos != 0
                           // Special case to fix problems with
                           // theorems (JMarc)
-                          || (layout->labeltype == LABEL_STATIC
-                              && layout->latextype == LATEX_ENVIRONMENT
+                          || (layout.labeltype == LABEL_STATIC
+                              && layout.latextype == LATEX_ENVIRONMENT
                               && !isFirstInSequence(pit, pars))) {
-                       l_margin += labelfont_metrics.signedWidth(layout->leftmargin);
-               } else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
-                          && layout->labeltype != LABEL_BIBLIO
-                          && layout->labeltype !=
+                       l_margin += labelfont_metrics.signedWidth(layout.leftmargin);
+               } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
+                          && layout.labeltype != LABEL_BIBLIO
+                          && layout.labeltype !=
                           LABEL_CENTERED_TOP_ENVIRONMENT) {
-                       l_margin += labelfont_metrics.signedWidth(layout->labelindent);
-                       l_margin += labelfont_metrics.width(layout->labelsep);
-                       l_margin += labelfont_metrics.width(par.getLabelstring());
+                       l_margin += labelfont_metrics.signedWidth(layout.labelindent);
+                       l_margin += labelfont_metrics.width(layout.labelsep);
+                       l_margin += labelfont_metrics.width(par.labelString());
                }
                break;
 
@@ -1786,7 +1806,7 @@ int TextMetrics::leftMargin(int max_width,
                for ( ; rit != end; ++rit)
                        if (rit->fill() < minfill)
                                minfill = rit->fill();
-               l_margin += theFontMetrics(params.getFont()).signedWidth(layout->leftmargin);
+               l_margin += theFontMetrics(params.getFont()).signedWidth(layout.leftmargin);
                l_margin += minfill;
 #endif
                // also wrong, but much shorter.
@@ -1801,29 +1821,30 @@ int TextMetrics::leftMargin(int max_width,
        LyXAlignment align;
 
        if (par.params().align() == LYX_ALIGN_LAYOUT)
-               align = layout->align;
+               align = layout.align;
        else
                align = par.params().align();
 
        // set the correct parindent
        if (pos == 0
-           && (layout->labeltype == LABEL_NO_LABEL
-              || layout->labeltype == LABEL_TOP_ENVIRONMENT
-              || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
-              || (layout->labeltype == LABEL_STATIC
-                  && layout->latextype == LATEX_ENVIRONMENT
-                  && !isFirstInSequence(pit, pars)))
+           && (layout.labeltype == LABEL_NO_LABEL
+              || layout.labeltype == LABEL_TOP_ENVIRONMENT
+              || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
+              || (layout.labeltype == LABEL_STATIC
+                  && layout.latextype == LATEX_ENVIRONMENT
+                  && !isFirstInSequence(pit, pars)))
            && align == LYX_ALIGN_BLOCK
            && !par.params().noindent()
            // in some insets, paragraphs are never indented
-           && !(par.inInset() && par.inInset()->neverIndent(buffer))
+           && !(par.inInset() && par.inInset()->neverIndent())
            // display style insets are always centered, omit indentation
            && !(!par.empty()
                    && par.isInset(pos)
                    && par.getInset(pos)->display())
-           && (par.layout() != tclass.defaultLayout()
-               || buffer.params().paragraph_separation ==
-                  BufferParams::PARSEP_INDENT))
+                       && ((tclass.isDefaultLayout(par.layout()) 
+                || tclass.isEmptyLayout(par.layout()))
+               || buffer.params().paragraph_separation == BufferParams::PARSEP_INDENT)
+           )
        {
                l_margin += theFontMetrics(buffer.params().getFont()).signedWidth(
                        parindent);
@@ -1837,7 +1858,7 @@ int TextMetrics::singleWidth(pit_type pit, pos_type pos) const
 {
        ParagraphMetrics const & pm = par_metrics_[pit];
 
-       return pm.singleWidth(pos, getDisplayFont(pit, pos));
+       return pm.singleWidth(pos, displayFont(pit, pos));
 }
 
 
@@ -1876,6 +1897,28 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
        int const ww = bv_->workHeight();
        size_t const nrows = pm.rows().size();
 
+       Cursor const & cur = bv_->cursor();
+       DocIterator sel_beg = cur.selectionBegin();
+       DocIterator sel_end = cur.selectionEnd();
+       bool selection = cur.selection()
+               // This is our text.
+               && cur.text() == text_
+               // if the anchor is outside, this is not our selection 
+               && cur.anchor().text() == text_
+               && pit >= sel_beg.pit() && pit <= sel_end.pit();
+
+       // We care only about visible selection.
+       if (selection) {
+               if (pit != sel_beg.pit()) {
+                       sel_beg.pit() = pit;
+                       sel_beg.pos() = 0;
+               }
+               if (pit != sel_end.pit()) {
+                       sel_end.pit() = pit;
+                       sel_end.pos() = sel_end.lastpos();
+               }
+       }
+
        for (size_t i = 0; i != nrows; ++i) {
 
                Row const & row = pm.rows()[i];
@@ -1888,6 +1931,11 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                pi.pain.setDrawingEnabled(inside && original_drawing_state);
                RowPainter rp(pi, *text_, pit, row, bidi, x, y);
 
+               if (selection)
+                       row.setSelection(sel_beg.pos(), sel_end.pos());
+               else
+                       row.setSelection(-1, -1);
+
                // Row signature; has row changed since last paint?
                row.setCrc(pm.computeRowSignature(row, bparams));
                bool row_has_changed = row.changed();