X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Frowpainter.cpp;h=6d56c27b60db69ccbb6743e91c3930cc8d68000e;hb=2455bc258f3b62c29ec4a41cb88070ff8518e842;hp=df83d9a40c8e1feda2a527b21843dbf3b7321b46;hpb=225bf49cf9ac251dc66e1ed1f2e4c1de503b01e1;p=lyx.git diff --git a/src/rowpainter.cpp b/src/rowpainter.cpp index df83d9a40c..6d56c27b60 100644 --- a/src/rowpainter.cpp +++ b/src/rowpainter.cpp @@ -10,6 +10,7 @@ */ #include +#include #include "rowpainter.h" @@ -17,7 +18,6 @@ #include "Buffer.h" #include "CoordCache.h" #include "Cursor.h" -#include "support/debug.h" #include "BufferParams.h" #include "BufferView.h" #include "Changes.h" @@ -40,12 +40,12 @@ #include "insets/InsetText.h" +#include "support/debug.h" #include "support/textutils.h" +#include "support/lassert.h" #include -#include - using namespace std; namespace lyx { @@ -69,14 +69,14 @@ 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_); + return text_.labelFont(pi_.base.bv->buffer(), par_); } @@ -93,9 +93,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, /**/); // Backup full_repaint status because some insets (InsetTabular) // requires a full repaint bool pi_full_repaint = pi_.full_repaint; @@ -124,7 +124,7 @@ void RowPainter::paintInset(Inset const * inset, pos_type const pos) #ifdef DEBUG_METRICS int const x1 = int(x_ - dim.width()); Dimension dim2; - BOOST_ASSERT(max_witdh_ > 0); + LASSERT(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); @@ -141,9 +141,9 @@ void RowPainter::paintInset(Inset const * inset, pos_type const pos) 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); + LASSERT(dim2.wid == dim.wid, /**/); + LASSERT(dim2.asc == dim.asc, /**/); + LASSERT(dim2.des == dim.des, /**/); int const x2 = x1 + dim.wid; int const y1 = yo_ + dim.des; int const y2 = yo_ - dim.asc; @@ -171,10 +171,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 +205,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 +224,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,13 +238,26 @@ 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::Type const change_type = par_.lookupChange(pos).type; + // selected text? + bool const selection = pos >= row_.sel_beg && pos < row_.sel_end; + // 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; + + if (change_type != par_.lookupChange(pos).type) + // Track change type has changed. break; char_type c = par_.getChar(pos); @@ -275,10 +284,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 +306,20 @@ 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 (!selection && change_type == Change::UNCHANGED) { x_ += pi_.pain.text(int(x_), yo_, s, font); + return; } + + FontInfo copy = font; + if (change_type == Change::DELETED) + copy.setColor(Color_deletedtext); + else if (change_type == Change::INSERTED) + copy.setColor(Color_addedtext); + else if (selection) + copy.setColor(Color_selectiontext); + + x_ += pi_.pain.text(int(x_), yo_, s, copy); } @@ -329,7 +341,7 @@ void RowPainter::paintForeignMark(double orig_x, Language const * lang, void RowPainter::paintFromPos(pos_type & vpos) { 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 @@ -343,8 +355,8 @@ void RowPainter::paintFromPos(pos_type & vpos) // 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()); @@ -473,17 +485,16 @@ void RowPainter::paintFirst() y_top += paintAppendixStart(yo_ - row_.ascent() + 2 * defaultRowHeight()); Buffer const & buffer = pi_.base.bv->buffer(); + Layout const & layout = par_.layout(); - LayoutPtr const & layout = par_.layout(); - - if (buffer.params().paragraph_separation == BufferParams::PARSEP_SKIP) { + if (buffer.params().paragraph_separation == BufferParams::ParagraphSkipSeparation) { if (pit_ != 0) { - if (layout->latextype == LATEX_PARAGRAPH + 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 + 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 += buffer.params().getDefSkip().inPixels(*pi_.base.bv); @@ -497,22 +508,22 @@ void RowPainter::paintFirst() //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_.getLabelstring(); + 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") { + if (layout.counter == "chapter") { double spacing_val = 1.0; if (!parparams.spacing().isDefault()) { spacing_val = parparams.spacing().getValue(); @@ -520,10 +531,10 @@ void RowPainter::paintFirst() spacing_val = buffer.params().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 +545,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,12 +558,12 @@ 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(); - if (!par_.getLabelstring().empty()) { - docstring const str = par_.getLabelstring(); + (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(); @@ -562,14 +573,14 @@ void RowPainter::paintFirst() 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; @@ -606,7 +617,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,9 +638,9 @@ 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(); + docstring const & str = par_.layout().endlabelstring(); double const x = is_rtl ? x_ - fm.width(str) : - text_metrics_.rightMargin(pm_) - row_.width(); @@ -674,12 +685,24 @@ 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; + // check for possible inline completion + DocIterator const & inlineCompletionPos = pi_.base.bv->inlineCompletionPos(); + pos_type inlineCompletionVPos = -1; + if (inlineCompletionPos.inTexted() + && inlineCompletionPos.text() == &text_ + && inlineCompletionPos.pit() == pit_ + && inlineCompletionPos.pos() - 1 >= row_.pos() + && inlineCompletionPos.pos() - 1 < row_.endpos()) { + // draw logically behind the previous character + inlineCompletionVPos = bidi_.log2vis(inlineCompletionPos.pos() - 1); + } + // Use font span to speed things up, see below FontSpan font_span; Font font; @@ -688,7 +711,7 @@ void RowPainter::paintText() // it's in the last row of a paragraph; see skipped_sep_vpos declaration if (end > 0 && end < par_.size() && par_.isSeparator(end - 1)) skipped_sep_vpos = bidi_.log2vis(end - 1); - + for (pos_type vpos = row_.pos(); vpos < end; ) { if (x_ > pi_.base.bv->workWidth()) break; @@ -709,7 +732,12 @@ 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 + && font_span.last > inlineCompletionVPos) + font_span.last = inlineCompletionVPos; } const int width_pos = pm_.singleWidth(pos, font); @@ -744,14 +772,18 @@ void RowPainter::paintText() } 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; } + + // Is the inline completion in front of character? + if (font.isRightToLeft() && vpos == inlineCompletionVPos) + 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) @@ -769,6 +801,10 @@ void RowPainter::paintText() // paint as many characters as possible. paintFromPos(vpos); } + + // Is the inline completion after character? + if (!font.isRightToLeft() && vpos - 1 == inlineCompletionVPos) + paintInlineCompletion(font); } // if we reach the end of a struck out range, paint it @@ -783,4 +819,39 @@ void RowPainter::paintText() } } + +void RowPainter::paintInlineCompletion(Font const & font) +{ + docstring completion = pi_.base.bv->inlineCompletion(); + FontInfo f = font.fontInfo(); + bool rtl = font.isRightToLeft(); + + // draw the unique and the non-unique completion part + // Note: this is not time-critical as it is + // only done once per screen. + 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(c1); + pi_.pain.text(int(x_), yo_, s1, f); + x_ += theFontMetrics(font).width(s1); + } + + if (s2.size() > 0) { + f.setColor(c2); + pi_.pain.text(int(x_), yo_, s2, f); + x_ += theFontMetrics(font).width(s2); + } +} + } // namespace lyx