]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Whitespace.
[lyx.git] / src / TextMetrics.cpp
index 20aa586a4424ccdf42246c9109de4dfcdce47cdd..f78594f54dad9860e42a6f2f05aedc13224edb32 100644 (file)
 #include "Length.h"
 #include "LyXRC.h"
 #include "MetricsInfo.h"
-#include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
 #include "ParIterator.h"
 #include "rowpainter.h"
 #include "Text.h"
 #include "TextClass.h"
 #include "VSpace.h"
+#include "WordLangTuple.h"
 
 #include "insets/InsetText.h"
 
 #include "frontends/Painter.h"
 
 #include "support/debug.h"
-#include <cstdlib>
+#include "support/docstring_list.h"
 #include "support/lassert.h"
 
+#include <cstdlib>
+
 using namespace std;
 
 
@@ -242,11 +244,9 @@ int TextMetrics::rightMargin(pit_type const pit) const
 
 void TextMetrics::applyOuterFont(Font & font) const
 {
-       Font lf(font_);
-       lf.fontInfo().reduce(bv_->buffer().params().getFont().fontInfo());
-       lf.fontInfo().realize(font.fontInfo());
-       lf.setLanguage(font.language());
-       font = lf;
+       FontInfo lf(font_.fontInfo());
+       lf.reduce(bv_->buffer().params().getFont().fontInfo());
+       font.fontInfo().realize(lf); 
 }
 
 
@@ -293,7 +293,7 @@ Font TextMetrics::displayFont(pit_type pit, pos_type pos) const
        // NOTE: the cast to pit_type should be removed when pit_type
        // changes to a unsigned integer.
        if (pit < pit_type(pars.size()))
-               font.fontInfo().realize(outerFont(pit, pars).fontInfo());
+               font.fontInfo().realize(text_->outerFont(pit).fontInfo());
 
        // Realize with the fonts of lesser depth.
        font.fontInfo().realize(params.getFont().fontInfo());
@@ -445,7 +445,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                        - right_margin;
                Font const & font = ii->inset->noFontChange() ?
                        bufferfont : displayFont(pit, ii->pos);
-               MacroContext mc(buffer, parPos);
+               MacroContext mc(&buffer, parPos);
                MetricsInfo mi(bv_, font.fontInfo(), w, mc);
                ii->inset->metrics(mi, dim);
                Dimension const old_dim = pm.insetDimension(ii->inset);
@@ -576,7 +576,7 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                        align = par.params().align();
 
                // handle alignment inside tabular cells
-               Inset const & owner = par.inInset();
+               Inset const & owner = text_->inset();
                switch (owner.contentAlignment()) {
                        case LYX_ALIGN_CENTER:
                        case LYX_ALIGN_LEFT:
@@ -792,8 +792,8 @@ private:
 
 } // anon namespace
 
-pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
-               pit_type pos) const
+pos_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
+               pos_type pos) const
 {
        ParagraphMetrics const & pm = par_metrics_[pit];
        Paragraph const & par = text_->getPar(pit);
@@ -829,11 +829,24 @@ pit_type TextMetrics::rowBreakPoint(int width, pit_type const pit,
        // pixel width since last breakpoint
        int chunkwidth = 0;
 
+       docstring const s(1, char_type(0x00B6));
+       Font f;
+       int par_marker_width = theFontMetrics(f).width(s);
+
        FontIterator fi = FontIterator(*this, par, pit, pos);
        pos_type point = end;
        pos_type i = pos;
+
+       ParagraphList const & pars_ = text_->paragraphs();
+       bool const draw_par_end_marker = lyxrc.paragraph_markers
+               && size_type(pit + 1) < pars_.size();
+                               
        for ( ; i < end; ++i, ++fi) {
                int thiswidth = pm.singleWidth(i, *fi);
+               
+               if (draw_par_end_marker && i == end - 1)
+                       // enlarge the last character to hold the end-of-par marker
+                       thiswidth += par_marker_width;
 
                // add inline completion width
                if (inlineCompletionLPos == i) {
@@ -947,7 +960,12 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
                                        w -= singleWidth(pit, i - 1);
                                w = max(w, label_end);
                        }
-                       w += pm.singleWidth(i, *fi);
+                       
+                       // a line separator at the end of a line (but not at the end of a 
+                       // paragraph) will not be drawn and should therefore not count for
+                       // the row width.
+                       if (!par.isLineSeparator(i) || i != end - 1 || end == par.size())
+                               w += pm.singleWidth(i, *fi);
 
                        // add inline completion width
                        if (inlineCompletionLPos == i) {
@@ -958,6 +976,18 @@ int TextMetrics::rowWidth(int right_margin, pit_type const pit,
                }
        }
 
+       // count the paragraph end marker.
+       if (end == par.size() && lyxrc.paragraph_markers) {
+               ParagraphList const & pars_ = text_->paragraphs();
+               if (size_type(pit + 1) < pars_.size()) {
+                       // enlarge the last character to hold the
+                       // end-of-par marker
+                       docstring const s(1, char_type(0x00B6));
+                       Font f;
+                       w += theFontMetrics(f).width(s);
+               }
+       }
+
        if (body_pos > 0 && body_pos >= end) {
                FontMetrics const & fm = theFontMetrics(
                        text_->labelFont(par));
@@ -1041,7 +1071,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
        ++maxdesc;
 
        ParagraphList const & pars = text_->paragraphs();
-       Inset const & inset = par.inInset();
+       Inset const & inset = text_->inset();
 
        // is it a top line?
        if (first == 0 && topBottomSpace) {
@@ -1075,7 +1105,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
                     || layout.labeltype == LABEL_BIBLIO
                     || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
-                   && isFirstInSequence(pit, pars)
+                   && text_->isFirstInSequence(pit)
                    && !par.labelString().empty())
                {
                        labeladdon = int(
@@ -1089,7 +1119,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                // a section, or between the items of a itemize or enumerate
                // environment.
 
-               pit_type prev = depthHook(pit, pars, par.getDepth());
+               pit_type prev = text_->depthHook(pit, par.getDepth());
                Paragraph const & prevpar = pars[prev];
                if (prev != pit
                    && prevpar.layout() == layout
@@ -1102,7 +1132,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
                                layoutasc = layout.topsep * dh;
                }
 
-               prev = outerHook(pit, pars);
+               prev = text_->outerHook(pit);
                if (prev != pit_type(pars.size())) {
                        maxasc += int(pars[prev].layout().parsep * dh);
                } else if (pit != 0) {
@@ -1127,7 +1157,7 @@ Dimension TextMetrics::rowHeight(pit_type const pit, pos_type const first,
 
                        if (pars[cpit].getDepth() > pars[nextpit].getDepth()) {
                                usual = pars[cpit].layout().bottomsep * dh;
-                               cpit = depthHook(cpit, pars, pars[nextpit].getDepth());
+                               cpit = text_->depthHook(cpit, pars[nextpit].getDepth());
                                if (pars[cpit].layout() != pars[nextpit].layout()
                                        || pars[nextpit].getLabelWidthString() != pars[cpit].getLabelWidthString())
                                {
@@ -1202,6 +1232,12 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
                return 0;
        }
 
+       // if the first character is a separator, we are in RTL
+       // text. This character will not be painted on screen
+       // and thus we should not count it and skip to the next.
+       if (par.isSeparator(bidi.vis2log(vc)))
+               ++vc;
+
        while (vc < end && tmpx <= x) {
                c = bidi.vis2log(vc);
                last_tmpx = tmpx;
@@ -1399,7 +1435,7 @@ pit_type TextMetrics::getPitNearY(int y)
 }
 
 
-Row const & TextMetrics::getPitAndRowNearY(int y, pit_type & pit,
+Row const & TextMetrics::getPitAndRowNearY(int y, pit_type & pit,
        bool assert_in_view, bool up)
 {
        ParagraphMetrics const & pm = par_metrics_[pit];
@@ -1413,25 +1449,29 @@ Row const & TextMetrics::getPitAndRowNearY(int y, pit_type & pit,
                if (yy + rit->height() > y)
                        break;
 
-       if (assert_in_view && yy + rit->height() != y) {
-               if (!up) {
-                       if (rit != pm.rows().begin())
+       if (assert_in_view) {
+               if (!up && yy + rit->height() > y) {
+                       if (rit != pm.rows().begin()) {
+                               y = yy;
                                --rit;
-                       else if (pit != 0) {
+                       else if (pit != 0) {
                                --pit;
                                newParMetricsUp();
                                ParagraphMetrics const & pm2 = par_metrics_[pit];
                                rit = pm2.rows().end();
                                --rit;
+                               y = yy;
                        }
-               } else  {
-                       if (rit != rlast)
+               } else if (up && yy != y) {
+                       if (rit != rlast) {
+                               y = yy + rit->height();
                                ++rit;
-                       else if (pit != int(par_metrics_.size())) {
+                       } else if (pit < int(text_->paragraphs().size()) - 1) {
                                ++pit;
                                newParMetricsDown();
                                ParagraphMetrics const & pm2 = par_metrics_[pit];
                                rit = pm2.rows().begin();
+                               y = pm2.position();
                        }
                }
        }
@@ -1450,10 +1490,11 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
        }
        pit_type pit = getPitNearY(y);
        LASSERT(pit != -1, return 0);
+       
+       int yy = y; // is modified by getPitAndRowNearY
+       Row const & row = getPitAndRowNearY(yy, pit, assert_in_view, up);
 
-       Row const & row = getPitAndRowNearY(y, pit, assert_in_view, up);
-       bool bound = false;
-
+       bool bound = false; // is modified by getColumnNearX
        int xx = x; // is modified by getColumnNearX
        pos_type const pos = row.pos()
                + getColumnNearX(pit, row, xx, bound);
@@ -1463,7 +1504,7 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
        cur.setTargetX(x);
 
        // try to descend into nested insets
-       Inset * inset = checkInsetHit(x, y);
+       Inset * inset = checkInsetHit(x, yy);
        //lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl;
        if (!inset) {
                // Either we deconst editXY or better we move current_font
@@ -1475,23 +1516,22 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
        }
 
        ParagraphList const & pars = text_->paragraphs();
-       Inset const * insetBefore = pos ? pars[pit].getInset(pos - 1) : 0;
-       //Inset * insetBehind = pars[pit].getInset(pos);
+       Inset const * inset_before = pos ? pars[pit].getInset(pos - 1) : 0;
 
        // This should be just before or just behind the
        // cursor position set above.
-       LASSERT((pos != 0 && inset == insetBefore)
+       LASSERT(inset == inset_before 
                || inset == pars[pit].getInset(pos), /**/);
 
        // Make sure the cursor points to the position before
        // this inset.
-       if (inset == insetBefore) {
+       if (inset == inset_before) {
                --cur.pos();
                cur.boundary(false);
        }
 
        // Try to descend recursively inside the inset.
-       inset = inset->editXY(cur, x, y);
+       inset = inset->editXY(cur, x, yy);
 
        if (cur.top().text() == text_)
                cur.setCurrentFont();
@@ -1618,6 +1658,8 @@ int TextMetrics::cursorX(CursorSlice const & sl,
        else if (ppos >= end)
                cursor_vpos = text_->isRTL(par) ? row_pos : end;
        else if (ppos > row_pos && ppos >= end)
+               //FIXME: this code is never reached!
+               //       (see http://www.lyx.org/trac/changeset/8251)
                // Place cursor after char at (logical) position pos - 1
                cursor_vpos = (bidi.level(ppos - 1) % 2 == 0)
                        ? bidi.log2vis(ppos - 1) + 1 : bidi.log2vis(ppos - 1);
@@ -1652,6 +1694,15 @@ int TextMetrics::cursorX(CursorSlice const & sl,
        if (end > 0 && end < par.size() && par.isSeparator(end - 1))
                skipped_sep_vpos = bidi.log2vis(end - 1);
 
+       if (lyxrc.paragraph_markers && text_->isRTL(par)) {
+               ParagraphList const & pars_ = text_->paragraphs();
+               if (size_type(pit + 1) < pars_.size()) {
+                       FontInfo f;
+                       docstring const s = docstring(1, char_type(0x00B6));
+                       x += theFontMetrics(f).width(s);
+               }
+       }
+
        // Inline completion RTL special case row_pos == cursor_pos:
        // "__|b" => cursor_pos is right of __
        if (row_pos == inlineCompletionVPos && row_pos == cursor_vpos) {
@@ -1845,7 +1896,7 @@ int TextMetrics::leftMargin(int max_width,
 
        if (par.getDepth() != 0) {
                // find the next level paragraph
-               pit_type newpar = outerHook(pit, pars);
+               pit_type newpar = text_->outerHook(pit);
                if (newpar != pit_type(pars.size())) {
                        if (pars[newpar].layout().isEnvironment()) {
                                l_margin = leftMargin(max_width, newpar);
@@ -1914,7 +1965,7 @@ int TextMetrics::leftMargin(int max_width,
                           // theorems (JMarc)
                           || (layout.labeltype == LABEL_STATIC
                               && layout.latextype == LATEX_ENVIRONMENT
-                              && !isFirstInSequence(pit, pars))) {
+                              && !text_->isFirstInSequence(pit))) {
                        l_margin += labelfont_metrics.signedWidth(layout.leftmargin);
                } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
                           && layout.labeltype != LABEL_BIBLIO
@@ -1963,7 +2014,7 @@ int TextMetrics::leftMargin(int max_width,
               || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
               || (layout.labeltype == LABEL_STATIC
                   && layout.latextype == LATEX_ENVIRONMENT
-                  && !isFirstInSequence(pit, pars)))
+                  && !text_->isFirstInSequence(pit)))
            && align == LYX_ALIGN_BLOCK
            && !par.params().noindent()
            // in some insets, paragraphs are never indented
@@ -2089,6 +2140,19 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                row.setCrc(pm.computeRowSignature(row, bparams));
                bool row_has_changed = row.changed();
 
+               // Take this opportunity to spellcheck the row contents.
+               if (row_has_changed && lyxrc.spellcheck_continuously) {
+                       WordLangTuple wl;
+                       // dummy variable, not used.
+                       static docstring_list suggestions;
+                       pos_type from = row.pos();
+                       pos_type to = row.endpos();
+                       while (from < row.endpos()) {
+                               text_->getPar(pit).spellCheck(from, to, wl, suggestions, false);
+                               from = to + 1;
+                       }
+               }
+
                // Don't paint the row if a full repaint has not been requested
                // and if it has not changed.
                if (!pi.full_repaint && !row_has_changed) {
@@ -2128,11 +2192,16 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                rp.paintAppendix();
                rp.paintDepthBar();
                rp.paintChangeBar();
-               if (i == 0)
+               bool const is_rtl = text_->isRTL(text_->getPar(pit));
+               if (i == 0 && !is_rtl)
                        rp.paintFirst();
+               if (i == nrows - 1 && is_rtl)
+                       rp.paintLast();
                rp.paintText();
-               if (i == nrows - 1)
+               if (i == nrows - 1 && !is_rtl)
                        rp.paintLast();
+               if (i == 0 && is_rtl)
+                       rp.paintFirst();
                y += row.descent();
                // Restore full_repaint status.
                pi.full_repaint = tmp;