X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=59eb2abd719269237c8314f32ccef4dc690b566e;hb=d0146c8e826d899c6a279a8ffba9be48a0293caa;hp=4dde5fd279b54deb381e410e13d4c9de01c53daa;hpb=45eb314a863a7bc76c2880f2352b7b430eeaf1c0;p=lyx.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 4dde5fd279..59eb2abd71 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -32,7 +32,7 @@ #include "LyXRC.h" #include "MetricsInfo.h" #include "ParagraphParameters.h" -#include "rowpainter.h" +#include "RowPainter.h" #include "Text.h" #include "TextClass.h" #include "VSpace.h" @@ -385,7 +385,7 @@ bool TextMetrics::redoParagraph(pit_type const pit) Cursor & cur = const_cast(bv_->cursor()); // In some cases, we do not know how to record undo if (&cur.inset() == &text_->inset()) - cur.recordUndo(ATOMIC_UNDO, pit, pit); + cur.recordUndo(pit, pit); int const moveCursor = par.fixBiblio(buffer); @@ -446,7 +446,7 @@ bool TextMetrics::redoParagraph(pit_type const pit) MacroContext mc(&buffer, parPos); MetricsInfo mi(bv_, font.fontInfo(), w, mc); ii->inset->metrics(mi, dim); - Dimension const old_dim = pm.insetDimension(ii->inset); + Dimension const & old_dim = pm.insetDimension(ii->inset); if (old_dim != dim) { pm.setInsetDimension(ii->inset, dim); changed = true; @@ -506,11 +506,11 @@ bool TextMetrics::redoParagraph(pit_type const pit) } -int TextMetrics::getAlign(Paragraph const & par, pos_type const pos) const +LyXAlignment TextMetrics::getAlign(Paragraph const & par, pos_type const pos) const { Layout const & layout = par.layout(); - int align; + LyXAlignment align; if (par.params().align() == LYX_ALIGN_LAYOUT) align = layout.align; else @@ -565,15 +565,15 @@ void TextMetrics::computeRowMetrics(pit_type const pit, Paragraph const & par = text_->getPar(pit); - double w = width - row.right_margin - row.width(); + int const w = width - row.right_margin - row.width(); // FIXME: put back this assertion when the crash on new doc is solved. //LASSERT(w >= 0, /**/); bool const is_rtl = text_->isRTL(par); if (is_rtl) - row.x = rightMargin(pit); + row.left_margin = rightMargin(pit); else - row.x = leftMargin(max_width_, pit, row.pos()); + row.left_margin = leftMargin(max_width_, pit, row.pos()); // is there a manual margin with a manual label Layout const & layout = par.layout(); @@ -600,69 +600,58 @@ void TextMetrics::computeRowMetrics(pit_type const pit, // are there any hfills in the row? if (int const nh = numberOfHfills(row, par.beginOfBody())) { if (w > 0) - hfill = w / double(nh); + hfill = double(w) / nh; // we don't have to look at the alignment if it is ALIGN_LEFT and // if the row is already larger then the permitted width as then // we force the LEFT_ALIGN'edness! } else if (int(row.width()) < max_width_) { // is it block, flushleft or flushright? // set x how you need it - int const align = getAlign(par, row.pos()); - - switch (align) { + switch (getAlign(par, row.pos())) { case LYX_ALIGN_BLOCK: { int const ns = numberOfSeparators(row); /** If we have separators, and this row has * not be broken abruptly by a display inset * or newline, then stretch it */ - if (ns && !row.right_boundary() + if (ns && !row.right_boundary() && row.endpos() != par.size()) { - setSeparatorWidth(row, w / ns); + setSeparatorWidth(row, double(w) / ns); row.dimension().wid = width; } else if (is_rtl) { row.dimension().wid = width; - row.x += w; + row.left_margin += w; } break; } case LYX_ALIGN_RIGHT: - row.x += w; + row.left_margin += w; break; case LYX_ALIGN_CENTER: row.dimension().wid = width - w / 2; - row.x += w / 2; + row.left_margin += w / 2; + break; + case LYX_ALIGN_LEFT: + case LYX_ALIGN_NONE: + case LYX_ALIGN_LAYOUT: + case LYX_ALIGN_SPECIAL: + case LYX_ALIGN_DECIMAL: break; } } -#if 0 - if (is_rtl) { - pos_type body_pos = par.beginOfBody(); - pos_type end = row.endpos(); - - if (body_pos > 0 - && (body_pos > end || !par.isLineSeparator(body_pos - 1))) { - row.x += theFontMetrics(text_->labelFont(par)). - width(layout.labelsep); - if (body_pos <= end) - row.x += row.label_hfill; - } - } -#endif - + // Finally, handle 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]; Row::iterator cit = row.begin(); Row::iterator const cend = row.end(); for ( ; cit != cend; ++cit) { if (row.label_hfill && cit->endpos == body_pos && cit->type == Row::SPACE) - cit->dim.wid -= row.label_hfill * (nlh - 1); + cit->dim.wid -= int(row.label_hfill * (nlh - 1)); if (!cit->inset || !cit->inset->isHfill()) continue; if (pm.hfillExpansion(row, cit->pos)) @@ -688,7 +677,7 @@ int TextMetrics::labelFill(pit_type const pit, Row const & row) const // iterate over elements before main body (except the last one, // which is extra space). while (cit!= end && cit->endpos < par.beginOfBody()) { - w += cit->width(); + w += cit->dim.wid; ++cit; } @@ -788,7 +777,7 @@ private: /** This is the function where the hard work is done. The code here is * very sensitive to small changes :) Note that part of the - * intelligence is also in Row::shorten_if_needed + * intelligence is also in Row::shortenIfNeeded. */ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit) const { @@ -798,12 +787,12 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit int const width = max_width_ - right_margin; pos_type const body_pos = par.beginOfBody(); row.clear(); - row.x = leftMargin(max_width_, pit, pos); - row.dimension().wid = row.x; + // This make get changed in computeRowMetrics depending on RTL + row.left_margin = leftMargin(max_width_, pit, pos); + row.dimension().wid = row.left_margin; row.right_margin = right_margin; if (pos >= end || row.width() > width) { - row.dimension().wid += right_margin; row.endpos(end); return; } @@ -846,6 +835,8 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit // before body_pos. Instead, insert some spacing to // align text FontMetrics const & fm = theFontMetrics(text_->labelFont(par)); + // this is needed to make sure that the row width is correct + row.finalizeLast(); int const add = max(fm.width(par.layout().labelsep), labelEnd(pit) - row.width()); row.addSpace(i, add, *fi, par.lookupChange(i)); @@ -909,12 +900,6 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit // if the row is too large, try to cut at last separator. row.shortenIfNeeded(body_pos, width); - // if the row ends with a separator that is not at end of - // paragraph, remove it - if (!row.empty() && row.back().type == Row::SEPARATOR - && row.endpos() < par.size()) - row.pop_back(); - // make sure that the RTL elements are in reverse ordering row.reverseRTL(text_->isRTL(par)); } @@ -1111,29 +1096,29 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x, pos_type pos = row.pos(); boundary = false; if (row.empty()) - x = row.x; - else if (x <= row.x) { + x = row.left_margin; + else if (x <= row.left_margin) { pos = row.front().left_pos(); - x = row.x; - } else if (x >= row.width() - row.right_margin) { + x = row.left_margin; + } else if (x >= row.width()) { pos = row.back().right_pos(); - x = row.width() - row.right_margin; + x = row.width(); } else { - double w = row.x; + double w = row.left_margin; Row::const_iterator cit = row.begin(); Row::const_iterator cend = row.end(); for ( ; cit != cend; ++cit) { - if (w <= x && w + cit->width() > x) { - double x_offset = x - w; + if (w <= x && w + cit->full_width() > x) { + int x_offset = int(x - w); pos = cit->x2pos(x_offset); - x = x_offset + w; + x = int(x_offset + w); break; } - w += cit->width(); + w += cit->full_width(); } if (cit == row.end()) { pos = row.back().right_pos(); - x = row.width() - row.right_margin; + x = row.width(); } /** This tests for the case where the cursor is placed * just before a font direction change. See comment on @@ -1147,12 +1132,14 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x, } /** This tests for the case where the cursor is set at the end - * of a row which has been broken due to a display inset on - * next row. This is indicated by Row::right_boundary. + * of a row which has been broken due something else than a + * separator (a display inset or a forced breaking of the + * row). We know that there is a separator when the end of the + * row is larger than the end of its last element. */ if (!row.empty() && pos == row.back().endpos && row.back().endpos == row.endpos()) - boundary = row.right_boundary(); + boundary = true; x += xo; return pos; @@ -1476,10 +1463,10 @@ int TextMetrics::cursorX(CursorSlice const & sl, if (row.empty() || (pos == row.begin()->left_pos() && pos != row.begin()->right_pos())) - return int(row.x); + return row.left_margin; Row::const_iterator cit = row.begin(); - double x = row.x; + double x = row.left_margin; for ( ; cit != row.end() ; ++cit) { /** Look whether the cursor is inside the element's * span. Note that it is necessary to take the @@ -1492,7 +1479,7 @@ int TextMetrics::cursorX(CursorSlice const & sl, x += cit->pos2x(pos); break; } - x += cit->width(); + x += cit->full_width(); } return int(x); @@ -1743,7 +1730,7 @@ int TextMetrics::leftMargin(int max_width, } if (!par.params().leftIndent().zero()) - l_margin += par.params().leftIndent().inPixels(max_width); + l_margin += par.params().leftIndent().inPixels(max_width, labelfont_metrics.em()); LyXAlignment align; @@ -1810,7 +1797,7 @@ void TextMetrics::draw(PainterInfo & pi, int x, int y) const } -void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) const +void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const x, int y) const { BufferParams const & bparams = bv_->buffer().params(); ParagraphMetrics const & pm = par_metrics_[pit]; @@ -1850,14 +1837,25 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co for (size_t i = 0; i != nrows; ++i) { Row const & row = pm.rows()[i]; + int row_x = x; if (i) y += row.ascent(); + CursorSlice rowSlice(const_cast(text_->inset())); + rowSlice.pit() = pit; + rowSlice.pos() = row.pos(); + bool const inside = (y + row.descent() >= 0 && y - row.ascent() < ww); + + // Adapt to cursor row scroll offset if applicable. + if (bv_->currentRowSlice() == rowSlice) + row_x -= bv_->horizScrollOffset(); + // It is not needed to draw on screen if we are not inside. pi.pain.setDrawingEnabled(inside && original_drawing_state); - RowPainter rp(pi, *text_, pit, row, x, y); + + RowPainter rp(pi, *text_, pit, row, row_x, y); if (selection) row.setSelectionAndMargins(sel_beg_par, sel_end_par); @@ -1874,8 +1872,10 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co } // Row signature; has row changed since last paint? - row.setCrc(pm.computeRowSignature(row, bparams)); - bool row_has_changed = row.changed(); + if (pi.pain.isDrawingEnabled()) + row.setCrc(pm.computeRowSignature(row, bparams)); + bool row_has_changed = row.changed() + || rowSlice == bv_->lastRowSlice(); // Take this opportunity to spellcheck the row contents. if (row_has_changed && lyxrc.spellcheck_continuously) { @@ -1895,7 +1895,10 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co // Clear background of this row if paragraph background was not // already cleared because of a full repaint. if (!pi.full_repaint && row_has_changed) { - pi.pain.fillRectangle(x, y - row.ascent(), + LYXERR(Debug::PAINTING, "Clear rect@(" + << max(row_x, 0) << ", " << y - row.ascent() << ")=" + << width() << " x " << row.height()); + pi.pain.fillRectangle(max(row_x, 0), y - row.ascent(), width(), row.height(), pi.background_color); } @@ -1908,7 +1911,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co LYXERR(Debug::PAINTING, foreword << "pit=" << pit << " row=" << i << " row_selection=" << row.selection() << " full_repaint=" << pi.full_repaint - << " row_has_changed=" << row_has_changed); + << " row_has_changed=" << row_has_changed + << " drawingEnabled=" << pi.pain.isDrawingEnabled()); } // Backup full_repaint status and force full repaint @@ -1930,6 +1934,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co rp.paintLast(); if (i == 0 && is_rtl) rp.paintFirst(); + rp.paintTooLargeMarks(row_x < 0, + row_x + row.width() > bv_->workWidth()); y += row.descent(); // Restore full_repaint status.