]> git.lyx.org Git - lyx.git/blobdiff - src/TextMetrics.cpp
Bug fix: correctly redraw a Row containing and inset which Dimension slightly changed...
[lyx.git] / src / TextMetrics.cpp
index fec9111b685c531501e57f1be89df110a5f21c20..3a529020785624bf4a015800749383a08b843a05 100644 (file)
@@ -115,7 +115,7 @@ TextMetrics::TextMetrics(BufferView * bv, Text * text)
        dim_.asc = 10;
        dim_.des = 10;
 
-       //text_->updateLabels(*bv->buffer());
+       //text_->updateLabels(bv->buffer());
 }
 
 
@@ -154,14 +154,14 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim)
        unsigned int w = 0;
        for (pit_type pit = 0, n = text_->paragraphs().size(); pit != n; ++pit) {
                changed |= redoParagraph(pit);
-               ParagraphMetrics const & pm = parMetrics(pit);
+               ParagraphMetrics const & pm = par_metrics_[pit];
                h += pm.height();
                if (w < pm.width())
                        w = pm.width();
        }
 
        dim.wid = w;
-       dim.asc = parMetrics(0).ascent();
+       dim.asc = par_metrics_[0].ascent();
        dim.des = h - dim.asc;
 
        changed |= dim_ != dim;
@@ -172,21 +172,26 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim)
 
 int TextMetrics::rightMargin(ParagraphMetrics const & pm) const
 {
-       return main_text_? pm.rightMargin(*bv_->buffer()) : 0;
+       return main_text_? pm.rightMargin(bv_->buffer()) : 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_->buffer()) : 0;
 }
 
 
 bool TextMetrics::redoParagraph(pit_type const pit)
 {
        Paragraph & par = text_->getPar(pit);
-       ParagraphMetrics pm(par);
-       Buffer & buffer = *bv_->buffer();
+       // IMPORTANT NOTE: We pass 'false' explicitely in order to not call
+       // redoParagraph() recursively inside parMetrics.
+       Dimension old_dim = parMetrics(pit, false).dim();
+       ParagraphMetrics & pm = par_metrics_[pit];
+       pm.reset(par);
+
+       Buffer & buffer = bv_->buffer();
        main_text_ = (text_ == &buffer.text());
        bool changed = false;
 
@@ -216,18 +221,17 @@ bool TextMetrics::redoParagraph(pit_type const pit)
        InsetList::const_iterator ii = par.insetlist.begin();
        InsetList::const_iterator iend = par.insetlist.end();
        for (; ii != iend; ++ii) {
+               Dimension old_dim = ii->inset->dimension();
                Dimension dim;
                int const w = max_width_ - text_->leftMargin(buffer, max_width_, pit, ii->pos)
                        - right_margin;
                Font const & font = ii->inset->noFontChange() ?
                        bufferfont : text_->getFont(buffer, par, ii->pos);
                MetricsInfo mi(bv_, font, w);
-               changed |= ii->inset->metrics(mi, dim);
+               ii->inset->metrics(mi, dim);
+               changed |= (old_dim != dim);
        }
 
-       // rebreak the paragraph
-       pm.rows().clear();
-
        par.setBeginOfBody();
        pos_type z = 0;
        // maximum pixel width of a row
@@ -257,17 +261,11 @@ bool TextMetrics::redoParagraph(pit_type const pit)
        pm.dim().asc += pm.rows()[0].ascent();
        pm.dim().des -= pm.rows()[0].ascent();
 
-       // IMPORTANT NOTE: We pass 'false' explicitely in order to not call
-       // redoParagraph() recursively inside parMetrics.
-       Dimension old_dim = parMetrics(pit, false).dim();
-
        changed |= old_dim.height() != pm.dim().height();
 
-       par_metrics_[pit] = pm;
-
        // Update the row change statuses. The painter will need that info
        // in order to know which row has to be repainted.
-       par_metrics_[pit].updateRowChangeStatus();
+       pm.updateRowChangeStatus();
 
        return changed;
 }
@@ -276,7 +274,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit,
                Row const & row) const
 {
        RowMetrics result;
-       Buffer & buffer = *bv_->buffer();
+       Buffer & buffer = bv_->buffer();
        Paragraph const & par = text_->getPar(pit);
 
        double w = dim_.wid - row.width();
@@ -288,7 +286,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit,
                result.x = text_->leftMargin(buffer, max_width_, pit, row.pos());
 
        // is there a manual margin with a manual label
-       Layout_ptr const & layout = par.layout();
+       LayoutPtr const & layout = par.layout();
 
        if (layout->margintype == MARGIN_MANUAL
            && layout->labeltype == LABEL_MANUAL) {
@@ -304,7 +302,7 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit,
                        ++nlh;
 
                if (nlh && !par.getLabelWidthString().empty())
-                       result.label_hfill = labelFill(par, row) / double(nlh);
+                       result.label_hfill = labelFill(pit, row) / double(nlh);
        }
 
        // are there any hfills in the row?
@@ -385,8 +383,8 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit,
                if (body_pos > 0
                    && (body_pos > end || !par.isLineSeparator(body_pos - 1)))
                {
-                       docstring const lsep = from_utf8(layout->labelsep);
-                       result.x += theFontMetrics(text_->getLabelFont(buffer, par)).width(lsep);
+                       result.x += theFontMetrics(text_->getLabelFont(buffer, par)).
+                               width(layout->labelsep);
                        if (body_pos <= end)
                                result.x += result.label_hfill;
                }
@@ -396,9 +394,10 @@ RowMetrics TextMetrics::computeRowMetrics(pit_type const pit,
 }
 
 
-int TextMetrics::labelFill(Paragraph const & par, Row const & row) const
+int TextMetrics::labelFill(pit_type const pit, Row const & row) const
 {
-       Buffer & buffer = *bv_->buffer();
+       Buffer & buffer = bv_->buffer();
+       Paragraph const & par = text_->getPar(pit);
 
        pos_type last = par.beginOfBody();
        BOOST_ASSERT(last > 0);
@@ -412,7 +411,7 @@ int TextMetrics::labelFill(Paragraph const & par, Row const & row) const
 
        int w = 0;
        for (pos_type i = row.pos(); i <= last; ++i)
-               w += text_->singleWidth(buffer, par, i);
+               w += singleWidth(pit, i);
 
        docstring const & label = par.params().labelWidthString();
        if (label.empty())
@@ -448,14 +447,15 @@ int TextMetrics::labelEnd(pit_type const pit) const
        if (text_->getPar(pit).layout()->margintype != MARGIN_MANUAL)
                return 0;
        // return the beginning of the body
-       return text_->leftMargin(*bv_->buffer(), max_width_, pit);
+       return text_->leftMargin(bv_->buffer(), max_width_, pit);
 }
 
 
 void TextMetrics::rowBreakPoint(int width, pit_type const pit,
                Row & row) const
 {
-       Buffer & buffer = *bv_->buffer();
+       Buffer & buffer = bv_->buffer();
+       ParagraphMetrics const & pm = par_metrics_[pit];
        Paragraph const & par = text_->getPar(pit);
        pos_type const end = par.size();
        pos_type const pos = row.pos();
@@ -469,7 +469,7 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit,
                return;
        }
 
-       Layout_ptr const & layout = par.layout();
+       LayoutPtr const & layout = par.layout();
 
        if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
                row.endpos(addressBreakPoint(pos, par));
@@ -493,17 +493,16 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit,
        FontIterator fi = FontIterator(buffer, *text_, par, pos);
        pos_type point = end;
        pos_type i = pos;
-       FontMetrics const & fm = theFontMetrics(text_->getLabelFont(buffer, par));
        for ( ; i < end; ++i, ++fi) {
-               char_type const c = par.getChar(i);
-               int thiswidth = text_->singleWidth(par, i, c, *fi);
+               int thiswidth = pm.singleWidth(i, *fi);
 
                // add the auto-hfill from label end to the body
                if (body_pos && i == body_pos) {
-                       docstring lsep = from_utf8(layout->labelsep);
-                       int add = fm.width(lsep);
+                       FontMetrics const & fm = theFontMetrics(
+                               text_->getLabelFont(buffer, par));
+                       int add = fm.width(layout->labelsep);
                        if (par.isLineSeparator(i - 1))
-                               add -= text_->singleWidth(buffer, par, i - 1);
+                               add -= singleWidth(pit, i - 1);
 
                        add = std::max(add, label_end - x);
                        thiswidth += add;
@@ -571,38 +570,38 @@ void TextMetrics::rowBreakPoint(int width, pit_type const pit,
 void TextMetrics::setRowWidth(int right_margin,
                pit_type const pit, Row & row) const
 {
-       Buffer & buffer = *bv_->buffer();
+       Buffer & buffer = bv_->buffer();
        // get the pure distance
        pos_type const end = row.endpos();
-
+       ParagraphMetrics const & pm = par_metrics_[pit];
        Paragraph const & par = text_->getPar(pit);
-       docstring const labelsep = from_utf8(par.layout()->labelsep);
        int w = text_->leftMargin(buffer, max_width_, pit, row.pos());
        int label_end = labelEnd(pit);
 
        pos_type const body_pos = par.beginOfBody();
        pos_type i = row.pos();
 
-       FontMetrics const & fm = theFontMetrics(text_->getLabelFont(buffer, par));
-
        if (i < end) {
                FontIterator fi = FontIterator(buffer, *text_, par, i);
                for ( ; i < end; ++i, ++fi) {
                        if (body_pos > 0 && i == body_pos) {
-                               w += fm.width(labelsep);
+                               FontMetrics const & fm = theFontMetrics(
+                                       text_->getLabelFont(buffer, par));
+                               w += fm.width(par.layout()->labelsep);
                                if (par.isLineSeparator(i - 1))
-                                       w -= text_->singleWidth(buffer, par, i - 1);
+                                       w -= singleWidth(pit, i - 1);
                                w = max(w, label_end);
                        }
-                       char_type const c = par.getChar(i);
-                       w += text_->singleWidth(par, i, c, *fi);
+                       w += pm.singleWidth(i, *fi);
                }
        }
 
        if (body_pos > 0 && body_pos >= end) {
-               w += fm.width(labelsep);
+               FontMetrics const & fm = theFontMetrics(
+                       text_->getLabelFont(buffer, par));
+               w += fm.width(par.layout()->labelsep);
                if (end > 0 && par.isLineSeparator(end - 1))
-                       w -= text_->singleWidth(buffer, par, end - 1);
+                       w -= singleWidth(pit, end - 1);
                w = max(w, label_end);
        }
 
@@ -622,13 +621,13 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
        // 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 :)
-       Layout_ptr const & layout = par.layout();
+       LayoutPtr 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();
+       Buffer const & buffer = bv_->buffer();
        Font font = text_->getFont(buffer, par, row.pos());
        Font::FONT_SIZE const tmpsize = font.size();
        font = text_->getLayoutFont(buffer, pit);
@@ -808,7 +807,7 @@ void TextMetrics::setHeightOfRow(pit_type const pit,
 pos_type TextMetrics::getColumnNearX(pit_type const pit,
                Row const & row, int & x, bool & boundary) const
 {
-       Buffer const & buffer = *bv_->buffer();
+       Buffer const & buffer = bv_->buffer();
 
        /// For the main Text, it is possible that this pit is not
        /// yet in the CoordCache when moving cursor up.
@@ -823,7 +822,7 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
        pos_type vc = row.pos();
        pos_type end = row.endpos();
        pos_type c = 0;
-       Layout_ptr const & layout = par.layout();
+       LayoutPtr const & layout = par.layout();
 
        bool left_side = false;
 
@@ -842,32 +841,29 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
                return 0;
        }
 
-       frontend::FontMetrics const & fm
-               = theFontMetrics(text_->getLabelFont(buffer, par));
-
        while (vc < end && tmpx <= x) {
                c = bidi.vis2log(vc);
                last_tmpx = tmpx;
                if (body_pos > 0 && c == body_pos - 1) {
-                       // FIXME UNICODE
-                       docstring const lsep = from_utf8(layout->labelsep);
-                       tmpx += r.label_hfill + fm.width(lsep);
+                       FontMetrics const & fm = theFontMetrics(
+                               text_->getLabelFont(buffer, par));
+                       tmpx += r.label_hfill + fm.width(layout->labelsep);
                        if (par.isLineSeparator(body_pos - 1))
-                               tmpx -= text_->singleWidth(buffer, par, body_pos - 1);
+                               tmpx -= singleWidth(pit, body_pos - 1);
                }
 
                if (par.hfillExpansion(row, c)) {
-                       tmpx += text_->singleWidth(buffer, par, c);
+                       tmpx += singleWidth(pit, c);
                        if (c >= body_pos)
                                tmpx += r.hfill;
                        else
                                tmpx += r.label_hfill;
                } else if (par.isSeparator(c)) {
-                       tmpx += text_->singleWidth(buffer, par, c);
+                       tmpx += singleWidth(pit, c);
                        if (c >= body_pos)
                                tmpx += r.separator;
                } else {
-                       tmpx += text_->singleWidth(buffer, par, c);
+                       tmpx += singleWidth(pit, c);
                }
                ++vc;
        }
@@ -914,9 +910,9 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
        // Newline inset, air gap below:
        if (row.pos() < end && c >= end && par.isNewline(end - 1)) {
                if (bidi.level(end -1) % 2 == 0)
-                       tmpx -= text_->singleWidth(buffer, par, end - 1);
+                       tmpx -= singleWidth(pit, end - 1);
                else
-                       tmpx += text_->singleWidth(buffer, par, end - 1);
+                       tmpx += singleWidth(pit, end - 1);
                c = end - 1;
        }
 
@@ -949,7 +945,7 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
 
 pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
 {
-       ParagraphMetrics const & pm = parMetrics(pit);
+       ParagraphMetrics const & pm = par_metrics_[pit];
        BOOST_ASSERT(!pm.rows().empty());
        BOOST_ASSERT(row < int(pm.rows().size()));
        bool bound = false;
@@ -958,9 +954,18 @@ pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
 }
 
 
+int TextMetrics::singleWidth(pit_type pit, pos_type pos) const
+{
+       Buffer const & buffer = bv_->buffer();
+       ParagraphMetrics const & pm = par_metrics_[pit];
+
+       return pm.singleWidth(pos, text_->getFont(buffer, text_->getPar(pit), pos));
+}
+
+
 //int Text::pos2x(pit_type pit, pos_type pos) const
 //{
-//     ParagraphMetrics const & pm = parMetrics(pit);
+//     ParagraphMetrics const & pm = par_metrics_[pit];
 //     Row const & r = pm.rows()[row];
 //     int x = 0;
 //     pos -= r.pos();