X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Frowpainter.cpp;h=080ef43f648a82ebfda240eee0e8f1da57d998d5;hb=77713af55868140483a1a7f5704dd93b97dbe116;hp=e4e48d6c5226246c2bb955ace995a68c854f328c;hpb=0fb8f3fba12ab9fb395ef40e21b5ba50a5e0b9df;p=lyx.git diff --git a/src/rowpainter.cpp b/src/rowpainter.cpp index e4e48d6c52..080ef43f64 100644 --- a/src/rowpainter.cpp +++ b/src/rowpainter.cpp @@ -10,6 +10,7 @@ */ #include +#include #include "rowpainter.h" @@ -21,7 +22,6 @@ #include "BufferView.h" #include "Changes.h" #include "Encoding.h" -#include "support/gettext.h" #include "Language.h" #include "Layout.h" #include "LyXRC.h" @@ -29,7 +29,6 @@ #include "MetricsInfo.h" #include "Paragraph.h" #include "ParagraphMetrics.h" -#include "paragraph_funcs.h" #include "ParagraphParameters.h" #include "TextMetrics.h" #include "VSpace.h" @@ -40,12 +39,12 @@ #include "insets/InsetText.h" #include "support/debug.h" +#include "support/gettext.h" #include "support/textutils.h" +#include "support/lassert.h" #include -#include - using namespace std; namespace lyx { @@ -60,7 +59,7 @@ RowPainter::RowPainter(PainterInfo & pi, pars_(text.paragraphs()), row_(row), pit_(pit), par_(text.paragraphs()[pit]), pm_(text_metrics_.parMetrics(pit)), - bidi_(bidi), erased_(pi_.erased_), + bidi_(bidi), change_(pi_.change_), xo_(x), yo_(y), width_(text_metrics_.width()) { bidi_.computeTables(par_, pi_.base.bv->buffer(), row_); @@ -69,14 +68,18 @@ RowPainter::RowPainter(PainterInfo & pi, //lyxerr << "RowPainter: x: " << x_ << " xo: " << xo_ << " yo: " << yo_ << endl; //row_.dump(); - BOOST_ASSERT(pit >= 0); - BOOST_ASSERT(pit < int(text.paragraphs().size())); + LASSERT(pit >= 0, /**/); + LASSERT(pit < int(text.paragraphs().size()), /**/); } -FontInfo const RowPainter::getLabelFont() const +FontInfo RowPainter::labelFont() const { - return text_.getLabelFont(pi_.base.bv->buffer(), par_); + FontInfo f = text_.labelFont(par_); + // selected text? + if (row_.begin_margin_sel || pi_.selected) + f.setPaintColor(Color_selectiontext); + return f; } @@ -93,9 +96,9 @@ int RowPainter::leftMargin() const void RowPainter::paintInset(Inset const * inset, pos_type const pos) { - Font const font = text_metrics_.getDisplayFont(pit_, pos); + Font const font = text_metrics_.displayFont(pit_, pos); - BOOST_ASSERT(inset); + LASSERT(inset, return); // Backup full_repaint status because some insets (InsetTabular) // requires a full repaint bool pi_full_repaint = pi_.full_repaint; @@ -106,11 +109,14 @@ void RowPainter::paintInset(Inset const * inset, pos_type const pos) pi_.base.bv->buffer().params().getFont().fontInfo() : font.fontInfo(); pi_.ltr_pos = (bidi_.level(pos) % 2 == 0); - pi_.erased_ = erased_ || par_.isDeleted(pos); - pi_.base.bv->coordCache().insets().add(inset, int(x_), yo_); + pi_.change_ = change_.changed() ? change_ : par_.lookupChange(pos); + + int const x1 = int(x_); + pi_.base.bv->coordCache().insets().add(inset, x1, yo_); // insets are painted completely. Recursive - inset->drawSelection(pi_, int(x_), yo_); - inset->draw(pi_, int(x_), yo_); + inset->drawBackground(pi_, x1, yo_); + inset->drawSelection(pi_, x1, yo_); + inset->draw(pi_, x1, yo_); Dimension const & dim = pm_.insetDimension(inset); @@ -122,28 +128,6 @@ void RowPainter::paintInset(Inset const * inset, pos_type const pos) pi_.full_repaint = pi_full_repaint; #ifdef DEBUG_METRICS - int const x1 = int(x_ - dim.width()); - Dimension dim2; - BOOST_ASSERT(max_witdh_ > 0); - int right_margin = text_metrics_.rightMargin(pm_); - int const w = max_witdh_ - leftMargin() - right_margin; - MetricsInfo mi(pi_.base.bv, font.fontInfo(), w); - inset->metrics(mi, dim2); - if (dim.wid != dim2.wid) - lyxerr << "Error: inset " << to_ascii(inset->getInsetName()) - << " draw width " << dim.width() - << "> metrics width " << dim2.wid << "." << endl; - if (dim->asc != dim2.asc) - lyxerr << "Error: inset " << to_ascii(inset->getInsetName()) - << " draw ascent " << dim.ascent() - << "> metrics ascent " << dim2.asc << "." << endl; - if (dim2.descent() != dim.des) - lyxerr << "Error: inset " << to_ascii(inset->getInsetName()) - << " draw ascent " << dim.descent() - << "> metrics descent " << dim2.des << "." << endl; - BOOST_ASSERT(dim2.wid == dim.wid); - BOOST_ASSERT(dim2.asc == dim.asc); - BOOST_ASSERT(dim2.des == dim.des); int const x2 = x1 + dim.wid; int const y1 = yo_ + dim.des; int const y2 = yo_ - dim.asc; @@ -171,10 +155,10 @@ void RowPainter::paintHebrewComposeChar(pos_type & vpos, FontInfo const & font) for (pos_type i = pos - 1; i >= 0; --i) { c = par_.getChar(i); - if (!Encodings::isComposeChar_hebrew(c)) { + if (!Encodings::isHebrewComposeChar(c)) { if (isPrintableNonspace(c)) { int const width2 = pm_.singleWidth(i, - text_metrics_.getDisplayFont(pit_, i)); + text_metrics_.displayFont(pit_, i)); dx = (c == 0x05e8 || // resh c == 0x05d3) // dalet ? width2 - width @@ -205,10 +189,10 @@ void RowPainter::paintArabicComposeChar(pos_type & vpos, FontInfo const & font) for (pos_type i = pos - 1; i >= 0; --i) { c = par_.getChar(i); - if (!Encodings::isComposeChar_arabic(c)) { + if (!Encodings::isArabicComposeChar(c)) { if (isPrintableNonspace(c)) { int const width2 = pm_.singleWidth(i, - text_metrics_.getDisplayFont(pit_, i)); + text_metrics_.displayFont(pit_, i)); dx = (width2 - width) / 2; } break; @@ -224,10 +208,6 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, { // This method takes up 70% of time when typing pos_type pos = bidi_.vis2log(vpos); - pos_type const end = row_.endpos(); - FontSpan const font_span = par_.fontSpan(pos); - Change::Type const prev_change = par_.lookupChange(pos).type; - // first character vector str; str.reserve(100); @@ -242,17 +222,49 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, str[0] = par_.transformChar(c, pos); } + pos_type const end = row_.endpos(); + FontSpan const font_span = par_.fontSpan(pos); + // Track-change status. + Change const & change_running = par_.lookupChange(pos); + + // selected text? + bool const selection = (pos >= row_.sel_beg && pos < row_.sel_end) + || pi_.selected; + + // spelling correct? + bool const spell_state = + lyxrc.spellcheck_continuously && par_.isMisspelled(pos); + + char_type prev_char = ' '; // collect as much similar chars as we can for (++vpos ; vpos < end ; ++vpos) { pos = bidi_.vis2log(vpos); if (pos < font_span.first || pos > font_span.last) break; - if (prev_change != par_.lookupChange(pos).type) + bool const new_selection = pos >= row_.sel_beg && pos < row_.sel_end; + if (new_selection != selection) + // Selection ends or starts here. + break; + + bool const new_spell_state = + lyxrc.spellcheck_continuously && par_.isMisspelled(pos); + if (new_spell_state != spell_state) + // Spell checker state changed here. + break; + + Change const & change = par_.lookupChange(pos); + if (!change_running.isSimilarTo(change)) + // Track change type or author has changed. break; char_type c = par_.getChar(pos); + if (c == '\t' || prev_char == '\t') { + prev_char = c; + break; + } + if (!isPrintableNonspace(c)) break; @@ -275,10 +287,10 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, * of arabic and hebrew characters, then these breaks may have * to be re-applied. - if (arabic && Encodings::isComposeChar_arabic(c)) + if (arabic && Encodings::isArabicComposeChar(c)) break; - if (hebrew && Encodings::isComposeChar_hebrew(c)) + if (hebrew && Encodings::isHebrewComposeChar(c)) break; */ @@ -297,17 +309,21 @@ void RowPainter::paintChars(pos_type & vpos, FontInfo const & font, docstring s(&str[0], str.size()); - if (prev_change != Change::UNCHANGED) { - FontInfo copy = font; - if (prev_change == Change::DELETED) { - copy.setColor(Color_deletedtext); - } else if (prev_change == Change::INSERTED) { - copy.setColor(Color_addedtext); - } - x_ += pi_.pain.text(int(x_), yo_, s, copy); - } else { + if (s[0] == '\t') + s.replace(0,1,from_ascii(" ")); + + if (!selection && !change_running.changed()) { x_ += pi_.pain.text(int(x_), yo_, s, font); + return; } + + FontInfo copy = font; + if (change_running.changed()) + copy.setPaintColor(change_running.color()); + else if (selection) + copy.setPaintColor(Color_selectiontext); + + x_ += pi_.pain.text(int(x_), yo_, s, copy); } @@ -326,10 +342,21 @@ void RowPainter::paintForeignMark(double orig_x, Language const * lang, } -void RowPainter::paintFromPos(pos_type & vpos) +void RowPainter::paintMisspelledMark(double orig_x, int desc, 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); + pi_.pain.line(int(orig_x), y, int(x_), y, Color_red, Painter::line_onoffdash, 1.0); +} + + +void RowPainter::paintFromPos(pos_type & vpos, bool changed) { pos_type const pos = bidi_.vis2log(vpos); - Font const orig_font = text_metrics_.getDisplayFont(pit_, pos); + Font const orig_font = text_metrics_.displayFont(pit_, pos); double const orig_x = x_; // usual characters, no insets @@ -341,10 +368,14 @@ void RowPainter::paintFromPos(pos_type & vpos) bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi" || lang == "farsi"; + // spelling correct? + bool const misspelled_ = + lyxrc.spellcheck_continuously && par_.isMisspelled(pos); + // draw as many chars as we can if ((!hebrew && !arabic) - || (hebrew && !Encodings::isComposeChar_hebrew(c)) - || (arabic && !Encodings::isComposeChar_arabic(c))) { + || (hebrew && !Encodings::isHebrewComposeChar(c)) + || (arabic && !Encodings::isArabicComposeChar(c))) { paintChars(vpos, orig_font.fontInfo(), hebrew, arabic); } else if (hebrew) { paintHebrewComposeChar(vpos, orig_font.fontInfo()); @@ -353,6 +384,10 @@ void RowPainter::paintFromPos(pos_type & vpos) } paintForeignMark(orig_x, orig_font.language()); + + if (lyxrc.spellcheck_continuously && misspelled_) { + paintMisspelledMark(orig_x, 2, changed); + } } @@ -381,7 +416,7 @@ void RowPainter::paintChangeBar() void RowPainter::paintAppendix() { // only draw the appendix frame once (for the main text) - if (!par_.params().appendix() || !text_.isMainText(pi_.base.bv->buffer())) + if (!par_.params().appendix() || !text_.isMainText()) return; int y = yo_ - row_.ascent(); @@ -421,7 +456,7 @@ void RowPainter::paintDepthBar() int const w = nestMargin() / 5; int x = int(xo_) + w * i; // only consider the changebar space if we're drawing outermost text - if (text_.isMainText(pi_.base.bv->buffer())) + if (text_.isMainText()) x += changebarMargin(); int const starty = yo_ - row_.ascent(); @@ -464,45 +499,43 @@ int RowPainter::paintAppendixStart(int y) void RowPainter::paintFirst() { - ParagraphParameters const & parparams = par_.params(); + ParagraphParameters const & pparams = par_.params(); + Buffer const & buffer = pi_.base.bv->buffer(); + BufferParams const & bparams = buffer.params(); + Layout const & layout = par_.layout(); int y_top = 0; // start of appendix? - if (parparams.startOfAppendix()) + if (pparams.startOfAppendix()) y_top += paintAppendixStart(yo_ - row_.ascent() + 2 * defaultRowHeight()); - Buffer const & buffer = pi_.base.bv->buffer(); - - LayoutPtr const & layout = par_.layout(); - - if (buffer.params().paragraph_separation == BufferParams::PARSEP_SKIP) { - if (pit_ != 0) { - if (layout->latextype == LATEX_PARAGRAPH - && !par_.getDepth()) { - y_top += buffer.params().getDefSkip().inPixels(*pi_.base.bv); - } else { - LayoutPtr const & playout = pars_[pit_ - 1].layout(); - if (playout->latextype == LATEX_PARAGRAPH - && !pars_[pit_ - 1].getDepth()) { - // is it right to use defskip here, too? (AS) - y_top += buffer.params().getDefSkip().inPixels(*pi_.base.bv); - } + if (bparams.paragraph_separation == BufferParams::ParagraphSkipSeparation + && pit_ != 0) { + if (layout.latextype == LATEX_PARAGRAPH + && !par_.getDepth()) { + y_top += bparams.getDefSkip().inPixels(*pi_.base.bv); + } else { + Layout const & playout = pars_[pit_ - 1].layout(); + if (playout.latextype == LATEX_PARAGRAPH + && !pars_[pit_ - 1].getDepth()) { + // is it right to use defskip here, too? (AS) + y_top += bparams.getDefSkip().inPixels(*pi_.base.bv); } } } - bool const is_rtl = text_.isRTL(buffer, par_); - bool const is_seq = isFirstInSequence(pit_, text_.paragraphs()); + 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 + if (layout.labeltype >= LABEL_STATIC + && (layout.labeltype != LABEL_STATIC + || layout.latextype != LATEX_ENVIRONMENT || is_seq)) { - FontInfo const font = getLabelFont(); + FontInfo const font = labelFont(); FontMetrics const & fm = theFontMetrics(font); docstring const str = par_.labelString(); @@ -512,18 +545,18 @@ void RowPainter::paintFirst() // 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") { + if (layout.counter == "chapter") { double spacing_val = 1.0; - if (!parparams.spacing().isDefault()) { - spacing_val = parparams.spacing().getValue(); + if (!pparams.spacing().isDefault()) { + spacing_val = pparams.spacing().getValue(); } else { - spacing_val = buffer.params().spacing().getValue(); + spacing_val = bparams.spacing().getValue(); } - int const labeladdon = int(fm.maxHeight() * layout->spacing.getValue() * spacing_val); + 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(); + int const maxdesc = int(fm.maxDescent() * layout.spacing.getValue() * spacing_val) + + int(layout.parsep) * defaultRowHeight(); if (is_rtl) { x = width_ - leftMargin() - @@ -534,9 +567,9 @@ void RowPainter::paintFirst() } else { if (is_rtl) { x = width_ - leftMargin() - + fm.width(layout->labelsep); + + fm.width(layout.labelsep); } else { - x = x_ - fm.width(layout->labelsep) + x = x_ - fm.width(layout.labelsep) - fm.width(str); } @@ -547,29 +580,29 @@ void RowPainter::paintFirst() // 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 = getLabelFont(); + (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 (!parparams.spacing().isDefault()) - spacing_val = parparams.spacing().getValue(); + if (!pparams.spacing().isDefault()) + spacing_val = pparams.spacing().getValue(); else - spacing_val = buffer.params().spacing().getValue(); + spacing_val = bparams.spacing().getValue(); FontMetrics const & fm = theFontMetrics(font); int const labeladdon = int(fm.maxHeight() - * layout->spacing.getValue() * spacing_val); + * layout.spacing.getValue() * spacing_val); int maxdesc = - int(fm.maxDescent() * layout->spacing.getValue() * spacing_val - + (layout->labelbottomsep * defaultRowHeight())); + int(fm.maxDescent() * layout.spacing.getValue() * spacing_val + + (layout.labelbottomsep * defaultRowHeight())); double x = x_; - if (layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { + if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) { if (is_rtl) x = leftMargin(); x += (width_ - text_metrics_.rightMargin(pm_) - leftMargin()) / 2; @@ -583,22 +616,62 @@ void RowPainter::paintFirst() } +/** Check if the current paragraph is the last paragraph in a + proof environment */ +static int getEndLabel(pit_type p, Text const & text) +{ + ParagraphList const & pars = text.paragraphs(); + pit_type pit = p; + depth_type par_depth = pars[p].getDepth(); + while (pit != pit_type(pars.size())) { + Layout const & layout = pars[pit].layout(); + int const endlabeltype = layout.endlabeltype; + + if (endlabeltype != END_LABEL_NO_LABEL) { + if (p + 1 == pit_type(pars.size())) + return endlabeltype; + + depth_type const next_depth = + pars[p + 1].getDepth(); + if (par_depth > next_depth || + (par_depth == next_depth && layout != pars[p + 1].layout())) + return endlabeltype; + break; + } + if (par_depth == 0) + break; + pit = text.outerHook(pit); + if (pit != pit_type(pars.size())) + par_depth = pars[pit].getDepth(); + } + return END_LABEL_NO_LABEL; +} + + void RowPainter::paintLast() { - bool const is_rtl = text_.isRTL(pi_.base.bv->buffer(), par_); - int const endlabel = getEndLabel(pit_, text_.paragraphs()); + bool const is_rtl = text_.isRTL(par_); + int const endlabel = getEndLabel(pit_, text_); // paint imaginary end-of-paragraph character - if (par_.isInserted(par_.size()) || par_.isDeleted(par_.size())) { - FontMetrics const & fm = theFontMetrics(pi_.base.bv->buffer().params().getFont()); + Change const & change = par_.lookupChange(par_.size()); + if (change.changed()) { + FontMetrics const & fm = + theFontMetrics(pi_.base.bv->buffer().params().getFont()); int const length = fm.maxAscent() / 2; - ColorCode col = par_.isInserted(par_.size()) ? Color_addedtext : Color_deletedtext; + Color col = change.color(); pi_.pain.line(int(x_) + 1, yo_ + 2, int(x_) + 1, yo_ + 2 - length, col, - Painter::line_solid, Painter::line_thick); - pi_.pain.line(int(x_) + 1 - length, yo_ + 2, int(x_) + 1, yo_ + 2, col, - Painter::line_solid, Painter::line_thick); + Painter::line_solid, 3); + + if (change.deleted()) { + pi_.pain.line(int(x_) + 1 - length, yo_ + 2, int(x_) + 1 + length, + yo_ + 2, col, Painter::line_solid, 3); + } else { + pi_.pain.line(int(x_) + 1 - length, yo_ + 2, int(x_) + 1, + yo_ + 2, col, Painter::line_solid, 3); + } } // draw an endlabel @@ -606,7 +679,7 @@ void RowPainter::paintLast() switch (endlabel) { case END_LABEL_BOX: case END_LABEL_FILLED_BOX: { - FontInfo const font = getLabelFont(); + FontInfo const font = labelFont(); FontMetrics const & fm = theFontMetrics(font); int const size = int(0.75 * fm.maxAscent()); int const y = yo_ - size; @@ -627,17 +700,23 @@ void RowPainter::paintLast() } case END_LABEL_STATIC: { - FontInfo const font = getLabelFont(); + FontInfo const font = labelFont(); FontMetrics const & fm = theFontMetrics(font); - docstring const & str = par_.layout()->endlabelstring(); - double const x = is_rtl ? - x_ - fm.width(str) - : - text_metrics_.rightMargin(pm_) - row_.width(); + docstring const & str = par_.layout().endlabelstring(); + double const x = is_rtl ? x_ - fm.width(str) : x_; pi_.pain.text(int(x), yo_, str, font); break; } case END_LABEL_NO_LABEL: + if (lyxrc.paragraph_markers && size_type(pit_ + 1) < pars_.size()) { + docstring const s = docstring(1, char_type(0x00B6)); + FontInfo f = FontInfo(); + FontMetrics const & fm = theFontMetrics(f); + f.setColor(Color_paragraphmarker); + pi_.pain.text(int(x_), yo_, s, f); + x_ += fm.width(s); + } break; } } @@ -645,16 +724,25 @@ void RowPainter::paintLast() void RowPainter::paintOnlyInsets() { + CoordCache const & cache = pi_.base.bv->coordCache(); pos_type const end = row_.endpos(); 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) continue; - if (x_ > pi_.base.bv->workWidth()) + if (x_ > pi_.base.bv->workWidth() + || !cache.getInsets().has(inset)) continue; - x_ = pi_.base.bv->coordCache().getInsets().x(inset); + x_ = cache.getInsets().x(inset); + + bool const pi_selected = pi_.selected; + Cursor const & cur = pi_.base.bv->cursor(); + if (cur.selection() && cur.text() == &text_ + && cur.normalAnchor().text() == &text_) + pi_.selected = row_.sel_beg <= pos && row_.sel_end > pos; paintInset(inset, pos); + pi_.selected = pi_selected; } } @@ -674,11 +762,10 @@ void RowPainter::paintText() body_pos = 0; } - LayoutPtr const & layout = par_.layout(); + Layout const & layout = par_.layout(); - bool running_strikeout = false; - bool is_struckout = false; - int last_strikeout_x = 0; + Change change_running; + int change_last_x = 0; // check for possible inline completion DocIterator const & inlineCompletionPos = pi_.base.bv->inlineCompletionPos(); @@ -686,8 +773,8 @@ void RowPainter::paintText() if (inlineCompletionPos.inTexted() && inlineCompletionPos.text() == &text_ && inlineCompletionPos.pit() == pit_ - && inlineCompletionPos.pos() >= row_.pos() - && inlineCompletionPos.pos() <= row_.endpos()) { + && inlineCompletionPos.pos() - 1 >= row_.pos() + && inlineCompletionPos.pos() - 1 < row_.endpos()) { // draw logically behind the previous character inlineCompletionVPos = bidi_.log2vis(inlineCompletionPos.pos() - 1); } @@ -721,7 +808,7 @@ void RowPainter::paintText() // Use font span to speed things up, see above if (vpos < font_span.first || vpos > font_span.last) { font_span = par_.fontSpan(vpos); - font = text_metrics_.getDisplayFont(pit_, vpos); + font = text_metrics_.displayFont(pit_, vpos); // split font span if inline completion is inside if (font_span.first <= inlineCompletionVPos @@ -736,33 +823,39 @@ void RowPainter::paintText() ++vpos; continue; } - - is_struckout = par_.isDeleted(pos); - - if (is_struckout && !running_strikeout) { - running_strikeout = true; - last_strikeout_x = int(x_); + Change const & change = par_.lookupChange(pos); + if (change.changed() && !change_running.changed()) { + change_running = change; + change_last_x = int(x_); } Inset const * inset = par_.getInset(pos); bool const highly_editable_inset = inset - && inset->editable() == Inset::HIGHLY_EDITABLE; + && inset->editable(); - // If we reach the end of a struck out range, paint it. + // If we reach the end of a change or if the author changes, paint it. // We also don't paint across things like tables - if (running_strikeout && (highly_editable_inset || !is_struckout)) { + if (change_running.changed() && (highly_editable_inset + || !change.changed() || !change_running.isSimilarTo(change))) { // Calculate 1/3 height of the buffer's default font FontMetrics const & fm = theFontMetrics(pi_.base.bv->buffer().params().getFont()); - int const middle = yo_ - fm.maxAscent() / 3; - pi_.pain.line(last_strikeout_x, middle, int(x_), middle, - Color_deletedtext, Painter::line_solid, Painter::line_thin); - running_strikeout = false; + 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); + + // Change might continue with a different author or type + if (change.changed() && !highly_editable_inset) { + change_running = change; + change_last_x = int(x_); + } else + change_running.setUnchanged(); } if (body_pos > 0 && pos == body_pos - 1) { - int const lwidth = theFontMetrics(getLabelFont()) - .width(layout->labelsep); + int const lwidth = theFontMetrics(labelFont()) + .width(layout.labelsep); x_ += row_.label_hfill + lwidth - width_pos; } @@ -772,7 +865,7 @@ void RowPainter::paintText() paintInlineCompletion(font); if (par_.isSeparator(pos)) { - Font const orig_font = text_metrics_.getDisplayFont(pit_, pos); + Font const orig_font = text_metrics_.displayFont(pit_, pos); double const orig_x = x_; x_ += width_pos; if (pos >= body_pos) @@ -783,12 +876,19 @@ void RowPainter::paintText() } else if (inset) { // If outer row has changed, nested insets are repaint completely. pi_.base.bv->coordCache().insets().add(inset, int(x_), yo_); + + bool const pi_selected = pi_.selected; + Cursor const & cur = pi_.base.bv->cursor(); + if (cur.selection() && cur.text() == &text_ + && cur.normalAnchor().text() == &text_) + pi_.selected = row_.sel_beg <= pos && row_.sel_end > pos; paintInset(inset, pos); + pi_.selected = pi_selected; ++vpos; } else { // paint as many characters as possible. - paintFromPos(vpos); + paintFromPos(vpos, change_running.changed()); } // Is the inline completion after character? @@ -797,14 +897,14 @@ void RowPainter::paintText() } // if we reach the end of a struck out range, paint it - if (running_strikeout) { - // calculate 1/3 height of the buffer's default font + if (change_running.changed()) { FontMetrics const & fm = theFontMetrics(pi_.base.bv->buffer().params().getFont()); - int const middle = yo_ - fm.maxAscent() / 3; - pi_.pain.line(last_strikeout_x, middle, int(x_), middle, - Color_deletedtext, Painter::line_solid, Painter::line_thin); - running_strikeout = false; + 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); + change_running.setUnchanged(); } } @@ -813,10 +913,7 @@ void RowPainter::paintInlineCompletion(Font const & font) { docstring completion = pi_.base.bv->inlineCompletion(); FontInfo f = font.fontInfo(); - - // right to left? - if (font.isRightToLeft()) - reverse(completion.begin(), completion.end()); + bool rtl = font.isRightToLeft(); // draw the unique and the non-unique completion part // Note: this is not time-critical as it is @@ -824,16 +921,24 @@ void RowPainter::paintInlineCompletion(Font const & font) size_t uniqueTo = pi_.base.bv->inlineCompletionUniqueChars(); docstring s1 = completion.substr(0, uniqueTo); docstring s2 = completion.substr(uniqueTo); + ColorCode c1 = Color_inlinecompletion; + ColorCode c2 = Color_nonunique_inlinecompletion; + // right to left? + if (rtl) { + swap(s1, s2); + swap(c1, c2); + } + if (s1.size() > 0) { - f.setColor(Color_inlinecompletion); - pi_.pain.text(x_, yo_, s1, f); + f.setColor(c1); + pi_.pain.text(int(x_), yo_, s1, f); x_ += theFontMetrics(font).width(s1); } if (s2.size() > 0) { - f.setColor(Color_nonunique_inlinecompletion); - pi_.pain.text(x_, yo_, s2, f); + f.setColor(c2); + pi_.pain.text(int(x_), yo_, s2, f); x_ += theFontMetrics(font).width(s2); } }