X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Frowpainter.cpp;h=c5cc772fe8ecbdf5a4ef29a7298ce3b12844b34c;hb=55a3dd7b346d29a52ba305a4558e9e380ef50f47;hp=d7e05593b88e3b1d83301be8f78cf3f5119b7078;hpb=14d57ba19e5c7ef83f492f9f87da194c14949687;p=lyx.git diff --git a/src/rowpainter.cpp b/src/rowpainter.cpp index d7e05593b8..c5cc772fe8 100644 --- a/src/rowpainter.cpp +++ b/src/rowpainter.cpp @@ -38,6 +38,8 @@ #include "insets/InsetText.h" +#include "mathed/InsetMath.h" + #include "support/debug.h" #include "support/gettext.h" #include "support/textutils.h" @@ -60,9 +62,29 @@ RowPainter::RowPainter(PainterInfo & pi, row_(row), pit_(pit), par_(text.paragraphs()[pit]), pm_(text_metrics_.parMetrics(pit)), bidi_(bidi), change_(pi_.change_), - xo_(x), yo_(y), width_(text_metrics_.width()) + xo_(x), yo_(y), width_(text_metrics_.width()), + solid_line_thickness_(1.0), solid_line_offset_(1), + dotted_line_thickness_(1.0), dotted_line_offset_(2) { bidi_.computeTables(par_, pi_.base.bv->buffer(), row_); + + if (lyxrc.zoom >= 200) { + // derive the line thickness from zoom factor + // the zoom is given in percent + // (increase thickness at 250%, 450% etc.) + solid_line_thickness_ = (float)(int((lyxrc.zoom + 50) / 200.0)); + // adjust line_offset_ too + solid_line_offset_ = 1 + int(0.5 * solid_line_thickness_); + } + if (lyxrc.zoom >= 100) { + // derive the line thickness from zoom factor + // the zoom is given in percent + // (increase thickness at 150%, 250% etc.) + dotted_line_thickness_ = (float)(int((lyxrc.zoom + 50) / 100.0)); + // adjust line_offset_ too + dotted_line_offset_ = int(0.5 * dotted_line_thickness_) + 1; + } + x_ = row_.x + xo_; //lyxerr << "RowPainter: x: " << x_ << " xo: " << xo_ << " yo: " << yo_ << endl; @@ -103,11 +125,8 @@ void RowPainter::paintInset(Inset const * inset, pos_type const pos) // requires a full repaint bool pi_full_repaint = pi_.full_repaint; - // FIXME: We should always use font, see documentation of - // noFontChange() in Inset.h. - pi_.base.font = inset->noFontChange() ? - pi_.base.bv->buffer().params().getFont().fontInfo() : - font.fontInfo(); + pi_.base.font = inset->inheritFont() ? font.fontInfo() : + pi_.base.bv->buffer().params().getFont().fontInfo(); pi_.ltr_pos = (bidi_.level(pos) % 2 == 0); pi_.change_ = change_.changed() ? change_ : par_.lookupChange(pos); @@ -211,9 +230,10 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, // This method takes up 70% of time when typing pos_type pos = bidi_.vis2log(vpos); // first character + char_type prev_char = par_.getChar(pos); vector str; str.reserve(100); - str.push_back(par_.getChar(pos)); + str.push_back(prev_char); if (arabic) { char_type c = str[0]; @@ -237,9 +257,19 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, bool const spell_state = lyxrc.spellcheck_continuously && par_.isMisspelled(pos); - char_type prev_char = 0; // collect as much similar chars as we can for (++vpos ; vpos < end ; ++vpos) { + // Work-around bug #6920 + // The bug can be reproduced with DejaVu font under Linux. + // The issue is that we compute the metrics character by character + // in ParagraphMetrics::singleWidth(); but we paint word by word + // for performance reason. + // Maybe a more general fix would be draw character by character + // for some predefined fonts on some platform. In arabic and + // Hebrew we already do paint this way. + if (prev_char == 'f' || lyxrc.force_paint_single_char) + break; + pos = bidi_.vis2log(vpos); if (pos < font_span.first || pos > font_span.last) break; @@ -268,17 +298,6 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, if (!isPrintableNonspace(c)) break; - // Work-around bug #6920 - // The bug can be reproduced with DejaVu font under Linux. - // The issue is that we compute the metrics character by character - // in ParagraphMetrics::singleWidth(); but we paint word by word - // for performance reason. - // Maybe a more general fix would be draw character by character - // for some predefined fonts on some platform. In arabic and - // Hebrew we already do paint this way. - if (prev_char == 'f') - break; - /* Because we do our own bidi, at this point the strings are * already in visual order. However, Qt also applies its own * bidi algorithm to strings that it paints to the screen. @@ -349,20 +368,21 @@ void RowPainter::paintForeignMark(double orig_x, Language const * lang, if (lang == pi_.base.bv->buffer().params().language) return; - int const y = yo_ + 1 + desc; - pi_.pain.line(int(orig_x), y, int(x_), y, Color_language); + int const y = yo_ + solid_line_offset_ + desc + int(solid_line_thickness_/2); + pi_.pain.line(int(orig_x), y, int(x_), y, Color_language, + Painter::line_solid, solid_line_thickness_); } -void RowPainter::paintMisspelledMark(double orig_x, int desc, bool changed) +void RowPainter::paintMisspelledMark(double orig_x, bool changed) { - // derive the offset from zoom factor specified by user in percent // if changed the misspelled marker gets placed slightly lower than normal // to avoid drawing at the same vertical offset - int const offset = int(1.5 * lyxrc.zoom / 100.0); // [percent] - int const y = yo_ + desc + (changed ? offset : 0) + 1; - pi_.pain.line(int(orig_x), y, int(x_), y, Color_misspelled, - Painter::line_onoffdash, 2.0); + float const y = yo_ + solid_line_offset_ + solid_line_thickness_ + + (changed ? solid_line_thickness_ + 1 : 0) + + dotted_line_offset_; + pi_.pain.line(int(orig_x), int(y), int(x_), int(y), Color_error, + Painter::line_onoffdash, dotted_line_thickness_); } @@ -382,7 +402,7 @@ void RowPainter::paintFromPos(pos_type & vpos, bool changed) lang == "farsi"; // spelling correct? - bool const misspelled_ = + bool const misspelled = lyxrc.spellcheck_continuously && par_.isMisspelled(pos); // draw as many chars as we can @@ -398,8 +418,23 @@ void RowPainter::paintFromPos(pos_type & vpos, bool changed) paintForeignMark(orig_x, orig_font.language()); - if (lyxrc.spellcheck_continuously && misspelled_) { - paintMisspelledMark(orig_x, 2, changed); + if (lyxrc.spellcheck_continuously && misspelled) { + // check for cursor position + // don't draw misspelled marker for words at cursor position + // we don't want to disturb the process of text editing + BufferView const * bv = pi_.base.bv; + DocIterator const nw = bv->cursor().newWord(); + bool new_word = false; + if (!nw.empty() && par_.id() == nw.paragraph().id()) { + pos_type cpos = nw.pos(); + if (cpos > 0 && cpos == par_.size() && !par_.isWordSeparator(cpos-1)) + --cpos; + else if (cpos > 0 && par_.isWordSeparator(cpos)) + --cpos; + new_word = par_.isSameSpellRange(pos, cpos) ; + } + if (!new_word) + paintMisspelledMark(orig_x, changed); } } @@ -512,15 +547,13 @@ int RowPainter::paintAppendixStart(int y) void RowPainter::paintFirst() { - ParagraphParameters const & pparams = par_.params(); - Buffer const & buffer = pi_.base.bv->buffer(); - BufferParams const & bparams = buffer.params(); + BufferParams const & bparams = pi_.base.bv->buffer().params(); Layout const & layout = par_.layout(); int y_top = 0; // start of appendix? - if (pparams.startOfAppendix()) + if (par_.params().startOfAppendix()) y_top += paintAppendixStart(yo_ - row_.ascent() + 2 * defaultRowHeight()); if (bparams.paragraph_separation == BufferParams::ParagraphSkipSeparation @@ -538,97 +571,114 @@ void RowPainter::paintFirst() } } - bool const is_rtl = text_.isRTL(par_); bool const is_seq = text_.isFirstInSequence(pit_); //lyxerr << "paintFirst: " << par_.id() << " is_seq: " << is_seq << endl; - // should we print a label? if (layout.labeltype >= LABEL_STATIC - && (layout.labeltype != LABEL_STATIC - || layout.latextype != LATEX_ENVIRONMENT - || is_seq)) { + && (layout.labeltype != LABEL_STATIC + || layout.latextype != LATEX_ENVIRONMENT + || is_seq)) { + paintLabel(); + } else if (is_seq + && (layout.labeltype == LABEL_TOP_ENVIRONMENT + || layout.labeltype == LABEL_BIBLIO + || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)) { + // the labels at the top of an environment. + // More or less for bibliography + paintTopLevelLabel(); + } +} - FontInfo const font = labelFont(); - FontMetrics const & fm = theFontMetrics(font); - docstring const str = par_.labelString(); - if (!str.empty()) { - double x = x_; - - // this is special code for the chapter layout. This is - // printed in an extra row and has a pagebreak at - // the top. - if (layout.counter == "chapter") { - double spacing_val = 1.0; - if (!pparams.spacing().isDefault()) { - spacing_val = pparams.spacing().getValue(); - } else { - spacing_val = bparams.spacing().getValue(); - } - - int const labeladdon = int(fm.maxHeight() * layout.spacing.getValue() * spacing_val); - - int const maxdesc = int(fm.maxDescent() * layout.spacing.getValue() * spacing_val) - + int(layout.parsep) * defaultRowHeight(); - - if (is_rtl) { - x = width_ - leftMargin() - - fm.width(str); - } - - pi_.pain.text(int(x), yo_ - maxdesc - labeladdon, str, font); - } else { - if (is_rtl) { - x = width_ - leftMargin() - + fm.width(layout.labelsep); - } else { - x = x_ - fm.width(layout.labelsep) - - fm.width(str); - } - - pi_.pain.text(int(x), yo_, str, font); - } +void RowPainter::paintLabel() +{ + docstring const str = par_.labelString(); + if (str.empty()) + return; + + BufferParams const & bparams = pi_.base.bv->buffer().params(); + bool const is_rtl = text_.isRTL(par_); + Layout const & layout = par_.layout(); + ParagraphParameters const & pparams = par_.params(); + FontInfo const font = labelFont(); + FontMetrics const & fm = theFontMetrics(font); + + double x = x_; + + // this is special code for the chapter layout. This is + // printed in an extra row and has a pagebreak at + // the top. + if (layout.counter == "chapter") { + double spacing_val = 1.0; + if (!pparams.spacing().isDefault()) { + spacing_val = pparams.spacing().getValue(); + } else { + spacing_val = bparams.spacing().getValue(); } - // the labels at the top of an environment. - // More or less for bibliography - } else if (is_seq && - (layout.labeltype == LABEL_TOP_ENVIRONMENT || - layout.labeltype == LABEL_BIBLIO || - layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)) { - FontInfo const font = labelFont(); - docstring const str = par_.labelString(); - if (!str.empty()) { - double spacing_val = 1.0; - if (!pparams.spacing().isDefault()) - spacing_val = pparams.spacing().getValue(); - else - spacing_val = bparams.spacing().getValue(); - - FontMetrics const & fm = theFontMetrics(font); - - int const labeladdon = int(fm.maxHeight() - * layout.spacing.getValue() * spacing_val); - - int maxdesc = - int(fm.maxDescent() * layout.spacing.getValue() * spacing_val - + (layout.labelbottomsep * defaultRowHeight())); - - double x = x_; - if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { - if (is_rtl) - x = leftMargin(); - x += (width_ - text_metrics_.rightMargin(pm_) - leftMargin()) / 2; - x -= fm.width(str) / 2; - } else if (is_rtl) { - x = width_ - leftMargin() - fm.width(str); - } - pi_.pain.text(int(x), yo_ - maxdesc - labeladdon, str, font); + int const labeladdon = int(fm.maxHeight() * layout.spacing.getValue() * spacing_val); + + int const maxdesc = int(fm.maxDescent() * layout.spacing.getValue() * spacing_val) + + int(layout.parsep) * defaultRowHeight(); + + if (is_rtl) { + x = width_ - leftMargin() - + fm.width(str); } + + pi_.pain.text(int(x), yo_ - maxdesc - labeladdon, str, font); + } else { + if (is_rtl) { + x = width_ - leftMargin() + + fm.width(layout.labelsep); + } else { + x = x_ - fm.width(layout.labelsep) + - fm.width(str); + } + + pi_.pain.text(int(x), yo_, str, font); } } +void RowPainter::paintTopLevelLabel() +{ + BufferParams const & bparams = pi_.base.bv->buffer().params(); + bool const is_rtl = text_.isRTL(par_); + ParagraphParameters const & pparams = par_.params(); + Layout const & layout = par_.layout(); + FontInfo const font = labelFont(); + docstring const str = par_.labelString(); + if (str.empty()) + return; + + double spacing_val = 1.0; + if (!pparams.spacing().isDefault()) + spacing_val = pparams.spacing().getValue(); + else + spacing_val = bparams.spacing().getValue(); + + FontMetrics const & fm = theFontMetrics(font); + + int const labeladdon = int(fm.maxHeight() + * layout.spacing.getValue() * spacing_val); + + int maxdesc = + int(fm.maxDescent() * layout.spacing.getValue() * spacing_val + + (layout.labelbottomsep * defaultRowHeight())); + + double x = x_; + if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { + if (is_rtl) + x = leftMargin(); + x += (width_ - text_metrics_.rightMargin(pm_) - leftMargin()) / 2; + x -= fm.width(str) / 2; + } else if (is_rtl) { + x = width_ - leftMargin() - fm.width(str); + } + pi_.pain.text(int(x), yo_ - maxdesc - labeladdon, str, font); +} + /** Check if the current paragraph is the last paragraph in a proof environment */ static int getEndLabel(pit_type p, Text const & text) @@ -742,7 +792,12 @@ void RowPainter::paintOnlyInsets() for (pos_type pos = row_.pos(); pos != end; ++pos) { // If outer row has changed, nested insets are repaint completely. Inset const * inset = par_.getInset(pos); - if (!inset) + bool const nested_inset = inset && + ((inset->asInsetMath() && + !inset->asInsetMath()->asMacroTemplate()) + || inset->asInsetText() + || inset->asInsetTabular()); + if (!nested_inset) continue; if (x_ > pi_.base.bv->workWidth() || !cache.getInsets().has(inset)) @@ -853,10 +908,10 @@ void RowPainter::paintText() // Calculate 1/3 height of the buffer's default font FontMetrics const & fm = theFontMetrics(pi_.base.bv->buffer().params().getFont()); - int const y_bar = change_running.deleted() ? - yo_ - fm.maxAscent() / 3 : yo_ + fm.maxAscent() / 6; - pi_.pain.line(change_last_x, y_bar, int(x_), y_bar, - change_running.color(), Painter::line_solid, 0.5); + float const y_bar = change_running.deleted() ? + yo_ - fm.maxAscent() / 3 : yo_ + 2 * solid_line_offset_ + solid_line_thickness_; + pi_.pain.line(change_last_x, int(y_bar), int(x_), int(y_bar), + change_running.color(), Painter::line_solid, solid_line_thickness_); // Change might continue with a different author or type if (change.changed() && !highly_editable_inset) { @@ -913,10 +968,10 @@ void RowPainter::paintText() if (change_running.changed()) { FontMetrics const & fm = theFontMetrics(pi_.base.bv->buffer().params().getFont()); - int const y_bar = change_running.deleted() ? - yo_ - fm.maxAscent() / 3 : yo_ + fm.maxAscent() / 6; - pi_.pain.line(change_last_x, y_bar, int(x_), y_bar, - change_running.color(), Painter::line_solid, 0.5); + float const y_bar = change_running.deleted() ? + yo_ - fm.maxAscent() / 3 : yo_ + 2 * solid_line_offset_ + solid_line_thickness_; + pi_.pain.line(change_last_x, int(y_bar), int(x_), int(y_bar), + change_running.color(), Painter::line_solid, solid_line_thickness_); change_running.setUnchanged(); } } @@ -951,21 +1006,21 @@ void RowPainter::paintSelection() // draw the margins if (row_.begin_margin_sel) { if (text_.isRTL(beg.paragraph())) { - pi_.pain.fillRectangle(xo_ + x1, y1, text_metrics_.width() - rm - x1, y2 - y1, - Color_selection); + pi_.pain.fillRectangle(int(xo_ + x1), y1, + text_metrics_.width() - rm - x1, y2 - y1, Color_selection); } else { - pi_.pain.fillRectangle(xo_ + lm, y1, x1 - lm, y2 - y1, + pi_.pain.fillRectangle(int(xo_ + lm), y1, x1 - lm, y2 - y1, Color_selection); } } if (row_.end_margin_sel) { if (text_.isRTL(beg.paragraph())) { - pi_.pain.fillRectangle(xo_ + lm, y1, x2 - lm, y2 - y1, + pi_.pain.fillRectangle(int(xo_ + lm), y1, x2 - lm, y2 - y1, Color_selection); } else { - pi_.pain.fillRectangle(xo_ + x2, y1, text_metrics_.width() - rm - x2, y2 - y1, - Color_selection); + pi_.pain.fillRectangle(int(xo_ + x2), y1, text_metrics_.width() - rm - x2, + y2 - y1, Color_selection); } } @@ -1009,8 +1064,8 @@ void RowPainter::paintSelection() if (!(cur < end) || draw_now) { x2 = text_metrics_.cursorX(cur.top(), cur.boundary()); - pi_.pain.fillRectangle(xo_ + min(x1,x2), y1, abs(x2 - x1), y2 - y1, - Color_selection); + pi_.pain.fillRectangle(int(xo_ + min(x1, x2)), y1, abs(x2 - x1), + y2 - y1, Color_selection); // reset x1, so it is set again next round (which will be on the // right side of a boundary or at the selection end)