X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FTextMetrics.cpp;h=88ea65541f044b596ff33fc63aa44020f4b7fd42;hb=89d9334e03c311a4a7585f40ad81880304d174d4;hp=fc610ad854b3370527c61bb76839d46b29355d0f;hpb=7cc4ceb89c184e51c4dc575b7a5c2928469b3f14;p=lyx.git diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index fc610ad854..88ea65541f 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -48,6 +48,8 @@ #include "support/convert.h" #include "support/debug.h" #include "support/lassert.h" +#include "support/lyxlib.h" +#include "support/RefChanger.h" #include #include @@ -183,6 +185,12 @@ ParagraphMetrics const & TextMetrics::parMetrics(pit_type pit) const } +ParagraphMetrics & TextMetrics::parMetrics(pit_type pit) +{ + return parMetrics(pit, true); +} + + void TextMetrics::newParMetricsDown() { pair const & last = *par_metrics_.rbegin(); @@ -233,7 +241,7 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width, // << " maxWidth: " << max_width_ << "\nfont: " << mi.base.font << endl; bool changed = false; - unsigned int h = 0; + int h = 0; for (pit_type pit = 0; pit != npar; ++pit) { // create rows, but do not set alignment yet changed |= redoParagraph(pit, false); @@ -555,28 +563,6 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows) if (row_index < pm.rows().size()) pm.rows().resize(row_index); - // FIXME: It might be better to move this in another method - // specially tailored for the main text. - // Top and bottom margin of the document (only at top-level) - if (text_->isMainText()) { - // original value was 20px, which is 0.2in at 100dpi - int const margin = bv_->zoomedPixels(20); - if (pit == 0) { - pm.rows().front().dim().asc += margin; - /* coverity thinks that we should update pm.dim().asc - * below, but all the rows heights are actually counted as - * part of the paragraph metric descent see loop above). - */ - // coverity[copy_paste_error] - pm.dim().des += margin; - } - ParagraphList const & pars = text_->paragraphs(); - if (pit + 1 == pit_type(pars.size())) { - pm.rows().back().dim().des += margin; - pm.dim().des += margin; - } - } - // The space above and below the paragraph. int const top = parTopSpacing(pit); pm.rows().front().dim().asc += top; @@ -587,6 +573,18 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows) pm.dim().asc += pm.rows()[0].ascent(); pm.dim().des -= pm.rows()[0].ascent(); + // Top and bottom margin of the document (only at top-level) + // FIXME: It might be better to move this in another method + // specially tailored for the main text. + if (text_->isMainText()) { + if (pit == 0) + pm.dim().asc += bv_->topMargin(); + ParagraphList const & pars = text_->paragraphs(); + if (pit + 1 == pit_type(pars.size())) { + pm.dim().des += bv_->bottomMargin(); + } + } + changed |= old_dim.height() != pm.dim().height(); return changed; @@ -595,7 +593,7 @@ bool TextMetrics::redoParagraph(pit_type const pit, bool const align_rows) LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const { - LyXAlignment align = par.getAlign(); + LyXAlignment align = par.getAlign(bv_->buffer().params()); // handle alignment inside tabular cells Inset const & owner = text_->inset(); @@ -620,19 +618,13 @@ LyXAlignment TextMetrics::getAlign(Paragraph const & par, Row const & row) const // Display-style insets should always be on a centered row if (Inset const * inset = par.getInset(row.pos())) { - switch (inset->display()) { - case Inset::AlignLeft: - align = LYX_ALIGN_BLOCK; - break; - case Inset::AlignCenter: - align = LYX_ALIGN_CENTER; - break; - case Inset::Inline: - // unchanged (use align) - break; - case Inset::AlignRight: - align = LYX_ALIGN_RIGHT; - break; + if (inset->rowFlags() & Inset::Display) { + if (inset->rowFlags() & Inset::AlignLeft) + align = LYX_ALIGN_BLOCK; + else if (inset->rowFlags() & Inset::AlignRight) + align = LYX_ALIGN_RIGHT; + else + align = LYX_ALIGN_CENTER; } } @@ -974,23 +966,22 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const } // Handle some situations that abruptly terminate the row - // - A newline inset - // - Before a display inset - // - After a display inset - Inset const * inset = 0; - if (par.isNewline(i) || par.isEnvSeparator(i) - || (i + 1 < end && (inset = par.getInset(i + 1)) - && inset->display()) - || (!row.empty() && row.back().inset - && row.back().inset->display())) { + // - Before an inset with BreakBefore + // - After an inset with BreakAfter + Inset const * prevInset = !row.empty() ? row.back().inset : 0; + Inset const * nextInset = (i + 1 < end) ? par.getInset(i + 1) : 0; + if ((nextInset && nextInset->rowFlags() & Inset::BreakBefore) + || (prevInset && prevInset->rowFlags() & Inset::BreakAfter)) { row.flushed(true); - // We will force a row creation after either - // - a newline; - // - a display inset followed by a end label. - need_new_row = - par.isNewline(i) - || (inset && inset->display() && i + 1 == end - && text_->getEndLabel(row.pit()) != END_LABEL_NO_LABEL); + // Force a row creation after this one if it is ended by + // an inset that either + // - has row flag RowAfter that enforces that; + // - or (1) did force the row breaking, (2) is at end of + // paragraph and (3) the said paragraph has an end label. + need_new_row = prevInset && + (prevInset->rowFlags() & Inset::RowAfter + || (prevInset->rowFlags() & Inset::BreakAfter && i + 1 == end + && text_->getEndLabel(row.pit()) != END_LABEL_NO_LABEL)); ++i; break; } @@ -1154,6 +1145,14 @@ void TextMetrics::setRowHeight(Row & row) const int maxasc = int(fm.maxAscent() * spacing_val); int maxdes = int(fm.maxDescent() * spacing_val); + // Take label string into account (useful if labelfont is large) + if (row.pos() == 0 && layout.labelIsInline()) { + FontInfo const labelfont = text_->labelFont(par); + FontMetrics const & lfm = theFontMetrics(labelfont); + maxasc = max(maxasc, int(lfm.maxAscent() * spacing_val)); + maxdes = max(maxdes, int(lfm.maxDescent() * spacing_val)); + } + // Find the ascent/descent of the row contents for (Row::Element const & e : row) { if (e.inset) { @@ -1338,7 +1337,7 @@ Row const & TextMetrics::getPitAndRowNearY(int & y, pit_type & pit, { ParagraphMetrics const & pm = par_metrics_[pit]; - int yy = pm.position() - pm.ascent(); + int yy = pm.position() - pm.rows().front().ascent(); LBUFERR(!pm.rows().empty()); RowList::const_iterator rit = pm.rows().begin(); RowList::const_iterator rlast = pm.rows().end(); @@ -1755,7 +1754,7 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const if (!par.params().leftIndent().zero()) l_margin += par.params().leftIndent().inPixels(max_width_, lfm.em()); - LyXAlignment align = par.getAlign(); + LyXAlignment align = par.getAlign(bv_->buffer().params()); // set the correct parindent if (pos == 0 @@ -1769,10 +1768,10 @@ int TextMetrics::leftMargin(pit_type const pit, pos_type const pos) const && !par.params().noindent() // in some insets, paragraphs are never indented && !text_->inset().neverIndent() - // display style insets are always centered, omit indentation + // display style insets do not need indentation && !(!par.empty() && par.isInset(pos) - && par.getInset(pos)->display()) + && par.getInset(pos)->rowFlags() & Inset::Display) && (!(tclass.isDefaultLayout(par.layout()) || tclass.isPlainLayout(par.layout())) || buffer.params().paragraph_separation @@ -1818,6 +1817,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const if (pm.rows().empty()) return; size_t const nrows = pm.rows().size(); + // Remember left and right margin for drawing math numbers + Changer changeleft = make_change(pi.leftx, x + leftMargin(pit)); + Changer changeright = make_change(pi.rightx, x + width() - rightMargin(pit)); // Use fast lane in nodraw stage. if (pi.pain.isNull()) { @@ -1864,6 +1866,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const } } + if (text_->isRTL(pit)) + swap(pi.leftx, pi.rightx); + for (size_t i = 0; i != nrows; ++i) { Row const & row = pm.rows()[i]; @@ -1919,15 +1924,15 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const LYXERR(Debug::PAINTING, "Clear rect@(" << max(row_x, 0) << ", " << y - row.ascent() << ")=" << width() << " x " << row.height()); - // FIXME: this is a hack. We know that at least this - // amount of pixels can be cleared on right and left. - // Doing so gets rid of caret ghosts when the cursor is at - // the begining/end of row. However, it will not work if - // the caret has a ridiculous width like 6. (see ticket - // #10797) - pi.pain.fillRectangle(max(row_x, 0) - Inset::TEXT_TO_INSET_OFFSET, - y - row.ascent(), - width() + 2 * Inset::TEXT_TO_INSET_OFFSET, + // FIXME: this is a hack. We clear an amount equal to + // cursor width. This will not work if the caret has a + // ridiculous width like 6. (see ticket #10797) + // This is the same formula as in GuiWorkArea. + int const caret_width = lyxrc.cursor_width + ? lyxrc.cursor_width + : 1 + int((lyxrc.currentZoom + 50) / 200.0); + pi.pain.fillRectangle(max(row_x, 0), y - row.ascent(), + width() + caret_width, row.height(), pi.background_color); } @@ -1971,7 +1976,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const static int count = 0; ++count; FontInfo fi(sane_font); - fi.setSize(FONT_SIZE_TINY); + fi.setSize(TINY_SIZE); fi.setColor(Color_red); pi.pain.text(row_x, y, convert(count), fi); #endif