]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Remove boost/format support
[lyx.git] / src / TextMetrics.cpp
index 889634adf5ec3c848bb75eb1a47bf7f6a54a2e2f..fdf0da692672c78798b2feb956187108df06c0b8 100644 (file)
@@ -80,15 +80,18 @@ int numberOfLabelHfills(Paragraph const & par, Row const & row)
        return n;
 }
 
-
-int numberOfHfills(Row const & row, pos_type const body_pos)
+// FIXME: this needs to be rewritten, probably by merging it into some
+// code that, besides counting, sets the active status of the space
+// inset in the row element.
+int numberOfHfills(Row const & row, ParagraphMetrics const & pm,
+                   pos_type const body_pos)
 {
        int n = 0;
        Row::const_iterator cit = row.begin();
        Row::const_iterator const end = row.end();
        for ( ; cit != end ; ++cit)
                if (cit->pos >= body_pos
-                   && cit->inset && cit->inset->isHfill())
+                   && cit->inset && pm.hfillExpansion(row, cit->pos))
                        ++n;
        return n;
 }
@@ -440,16 +443,25 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                if (row_index == pm.rows().size())
                        pm.rows().push_back(Row());
                Row & row = pm.rows()[row_index];
+               row.pit(pit);
                row.pos(first);
                breakRow(row, right_margin, pit);
                setRowHeight(row, pit);
                row.setChanged(false);
-               if (row_index || row.right_boundary() || row.endpos() < par.size())
-                       // If there is more than one row or the row has been
-                       // broken by a display inset or a newline, expand the text
-                       // to the full allowable width. This setting here is
-                       // needed for the computeRowMetrics() below.
-                       dim_.wid = max_width_;
+               if (row_index || row.endpos() < par.size()
+                   || (row.right_boundary() && par.inInset().lyxCode() != CELL_CODE)) {
+                       /* If there is more than one row or the row has been
+                        * broken by a display inset or a newline, expand the text
+                        * to the full allowable width. This setting here is
+                        * needed for the computeRowMetrics() below. In the case
+                        * of a display inset, we do nothing when inside a table
+                        * cell, because the tabular code is not prepared for
+                        * that, and it triggers when using a caption in a
+                        * longtable (see bugs #9945 and #9757).
+                        */
+                       if (dim_.wid < max_width_)
+                               dim_.wid = max_width_;
+               }
                int const max_row_width = max(dim_.wid, row.width());
                computeRowMetrics(pit, row, max_row_width);
                first = row.endpos();
@@ -469,7 +481,7 @@ bool TextMetrics::redoParagraph(pit_type const pit)
                        pm.rows().push_back(Row());
                Row & row = pm.rows()[row_index];
                row.pos(first);
-               row.endpos(first);
+               breakRow(row, right_margin, pit);
                setRowHeight(row, pit);
                row.setChanged(false);
                int const max_row_width = max(dim_.wid, row.width());
@@ -585,21 +597,20 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
        }
 
        // are there any hfills in the row?
-       int nh = numberOfHfills(row, par.beginOfBody());
+       ParagraphMetrics & pm = par_metrics_[pit];
+       int nh = numberOfHfills(row, pm, par.beginOfBody());
        int hfill = 0;
        int hfill_rem = 0;
 
-       // We don't have to look at the alignment if
-       // * we use hfills, or
-       // * the row is already larger then the permitted width as then we
-       //   force the LEFT_ALIGN'edness!
-       if (nh > 0) {
-               hfill = w / nh;
-               hfill_rem = w % nh;
-               row.dimension().wid += w;
-       } else if (nh == 0 && int(row.width()) < max_width_) {
-               // is it block, flushleft or flushright?
-               // set x how you need it
+       // We don't have to look at the alignment if the row is already
+       // larger then the permitted width as then we force the
+       // LEFT_ALIGN'edness!
+       if (int(row.width()) >= max_width_)
+               return;
+
+       if (nh == 0) {
+               // Common case : there is no hfill, and the alignment will be
+               // meaningful
                switch (getAlign(par, row)) {
                case LYX_ALIGN_BLOCK: {
                        int const ns = row.countSeparators();
@@ -628,15 +639,19 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                case LYX_ALIGN_DECIMAL:
                        break;
                }
+               return;
        }
 
-       // Finally,  handle hfill insets
+       hfill = w / nh;
+       hfill_rem = w % nh;
+       row.dimension().wid += w;
+       // Set size of hfill insets
        pos_type const endpos = row.endpos();
        pos_type body_pos = par.beginOfBody();
        if (body_pos > 0
            && (body_pos > endpos || !par.isLineSeparator(body_pos - 1)))
                body_pos = 0;
-       ParagraphMetrics & pm = par_metrics_[pit];
+
        CoordCache::Insets & insetCache = bv_->coordCache().insets();
        Row::iterator cit = row.begin();
        Row::iterator const cend = row.end();
@@ -644,9 +659,7 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                if (row.label_hfill && cit->endpos == body_pos
                    && cit->type == Row::SPACE)
                        cit->dim.wid -= int(row.label_hfill * (nlh - 1));
-               if (!cit->inset || !cit->inset->isHfill())
-                       continue;
-               if (pm.hfillExpansion(row, cit->pos)) {
+               if (cit->inset && pm.hfillExpansion(row, cit->pos)) {
                        if (cit->pos >= body_pos) {
                                cit->dim.wid += hfill;
                                --nh;
@@ -654,9 +667,9 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
                                        cit->dim.wid += hfill_rem;
                        } else
                                cit->dim.wid += int(row.label_hfill);
+                       // Cache the inset dimension.
+                       insetCache.add(cit->inset, cit->dim);
                }
-               // Cache the inset dimension.
-               insetCache.add(cit->inset, cit->dim);
        }
 }
 
@@ -781,6 +794,7 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
        pos_type const pos = row.pos();
        pos_type const body_pos = par.beginOfBody();
        bool const is_rtl = text_->isRTL(par);
+       bool need_new_row = false;
 
        row.clear();
        row.left_margin = leftMargin(max_width_, pit, pos);
@@ -793,11 +807,6 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
        // the width available for the row.
        int const width = max_width_ - row.right_margin;
 
-       if (pos >= end || row.width() > width) {
-               row.endpos(end);
-               return;
-       }
-
        ParagraphList const & pars = text_->paragraphs();
 
 #if 0
@@ -818,7 +827,10 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
        // or the end of the par, then build a representation of the row.
        pos_type i = pos;
        FontIterator fi = FontIterator(*this, par, pit, pos);
-       while (i < end && row.width() <= width) {
+       do {
+               // this can happen for an empty row after a newline
+               if (i >= end)
+                       break;
                char_type c = par.getChar(i);
                // The most special cases are handled first.
                if (par.isInset(i)) {
@@ -877,18 +889,19 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
                    || (!row.empty() && row.back().inset
                        && row.back().inset->display())) {
                        row.right_boundary(true);
+                       need_new_row = par.isNewline(i);
                        ++i;
                        break;
                }
 
                ++i;
                ++fi;
-       }
+       } while (i < end && row.width() <= width);
        row.finalizeLast();
        row.endpos(i);
 
        // End of paragraph marker
-       if (lyxrc.paragraph_markers
+       if (lyxrc.paragraph_markers && !need_new_row
            && i == end && size_type(pit + 1) < pars.size()) {
                // add a virtual element for the end-of-paragraph
                // marker; it is shown on screen, but does not exist
@@ -901,8 +914,10 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
                row.addVirtual(end, docstring(1, char_type(0x00B6)), f, Change());
        }
 
-       // if the row is too large, try to cut at last separator.
-       row.shortenIfNeeded(body_pos, width);
+       // if the row is too large, try to cut at last separator. In case
+       // of success, reset indication that the row was broken abruptly.
+       if (row.shortenIfNeeded(body_pos, width))
+               row.right_boundary(false);
 
        // make sure that the RTL elements are in reverse ordering
        row.reverseRTL(is_rtl);
@@ -1099,6 +1114,16 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
        int const xo = origin_.x_;
        x -= xo;
 
+       int offset = 0;
+       CursorSlice rowSlice(const_cast<InsetText &>(text_->inset()));
+       rowSlice.pit() = row.pit();
+       rowSlice.pos() = row.pos();
+
+       // Adapt to cursor row scroll offset if applicable.
+       if (bv_->currentRowSlice() == rowSlice)
+               offset = bv_->horizScrollOffset();
+       x += offset;
+
        pos_type pos = row.pos();
        boundary = false;
        if (row.empty())
@@ -1144,11 +1169,18 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
         * row is larger than the end of its last element.
         */
        if (!row.empty() && pos == row.back().endpos
-           && row.back().endpos == row.endpos())
-               boundary = true;
+           && row.back().endpos == row.endpos()) {
+               Inset const * inset = row.back().inset;
+               if (inset && (inset->lyxCode() == NEWLINE_CODE
+                             || inset->lyxCode() == SEPARATOR_CODE))
+                       pos = row.back().pos;
+               else
+                       boundary = row.right_boundary();
+       }
 
-       x += xo;
+       x += xo - offset;
        //LYXERR0("getPosNearX ==> pos=" << pos << ", boundary=" << boundary);
+
        return pos;
 }
 
@@ -1577,7 +1609,8 @@ bool TextMetrics::cursorEnd(Cursor & cur)
                        boundary = true;
                else
                        --end;
-       }
+       } else if (cur.paragraph().isEnvSeparator(end-1))
+               --end;
        return text_->setCursor(cur, cur.pit(), end, true, boundary);
 }