From 2bff0157b6f2738723720e429e66e2a138b2d0d0 Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Fri, 31 Aug 2007 10:05:12 +0000 Subject: [PATCH] Transfer Text::drawSelection() to TextMetrics. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19940 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/BufferView.cpp | 2 +- src/Text.cpp | 163 ----------------------------------- src/Text.h | 6 -- src/TextMetrics.cpp | 160 ++++++++++++++++++++++++++++++++++ src/TextMetrics.h | 10 ++- src/insets/InsetText.cpp | 2 +- src/mathed/InsetMathMBox.cpp | 2 +- 7 files changed, 172 insertions(+), 173 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index f3d3590c5d..2ae81ea93f 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1550,7 +1550,7 @@ void BufferView::draw(frontend::Painter & pain) TextMetrics const & tm = text_metrics_[&text]; if (select) - text.drawSelection(pi, 0, 0); + tm.drawSelection(pi, 0, 0); int yy = metrics_info_.y1; // draw contents diff --git a/src/Text.cpp b/src/Text.cpp index 99e87889e1..09606366ac 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -1353,169 +1353,6 @@ bool Text::dissolveInset(Cursor & cur) { } -// only used for inset right now. should also be used for main text -void Text::drawSelection(PainterInfo & pi, int x, int) const -{ - Cursor & cur = pi.base.bv->cursor(); - if (!cur.selection()) - return; - if (!ptr_cmp(cur.text(), this)) - return; - - LYXERR(Debug::DEBUG) - << BOOST_CURRENT_FUNCTION - << "draw selection at " << x - << endl; - - DocIterator beg = cur.selectionBegin(); - DocIterator end = cur.selectionEnd(); - - BufferView & bv = *pi.base.bv; - - // the selection doesn't touch the visible screen? - if (bv_funcs::status(&bv, beg) == bv_funcs::CUR_BELOW - || bv_funcs::status(&bv, end) == bv_funcs::CUR_ABOVE) - return; - - TextMetrics const & tm = bv.textMetrics(this); - ParagraphMetrics const & pm1 = tm.parMetrics(beg.pit()); - ParagraphMetrics const & pm2 = tm.parMetrics(end.pit()); - Row const & row1 = pm1.getRow(beg.pos(), beg.boundary()); - Row const & row2 = pm2.getRow(end.pos(), end.boundary()); - - // clip above - int middleTop; - bool const clipAbove = - (bv_funcs::status(&bv, beg) == bv_funcs::CUR_ABOVE); - if (clipAbove) - middleTop = 0; - else - middleTop = bv_funcs::getPos(bv, beg, beg.boundary()).y_ + row1.descent(); - - // clip below - int middleBottom; - bool const clipBelow = - (bv_funcs::status(&bv, end) == bv_funcs::CUR_BELOW); - if (clipBelow) - middleBottom = bv.workHeight(); - else - middleBottom = bv_funcs::getPos(bv, end, end.boundary()).y_ - row2.ascent(); - - // start and end in the same line? - if (!(clipAbove || clipBelow) && &row1 == &row2) - // then only draw this row's selection - drawRowSelection(pi, x, row1, beg, end, false, false); - else { - if (!clipAbove) { - // get row end - DocIterator begRowEnd = beg; - begRowEnd.pos() = row1.endpos(); - begRowEnd.boundary(true); - - // draw upper rectangle - drawRowSelection(pi, x, row1, beg, begRowEnd, false, true); - } - - if (middleTop < middleBottom) { - // draw middle rectangle - pi.pain.fillRectangle(x, middleTop, - tm.width(), middleBottom - middleTop, - Color::selection); - } - - if (!clipBelow) { - // get row begin - DocIterator endRowBeg = end; - endRowBeg.pos() = row2.pos(); - endRowBeg.boundary(false); - - // draw low rectangle - drawRowSelection(pi, x, row2, endRowBeg, end, true, false); - } - } -} - - -void Text::drawRowSelection(PainterInfo & pi, int x, Row const & row, - DocIterator const & beg, DocIterator const & end, - bool drawOnBegMargin, bool drawOnEndMargin) const -{ - BufferView & bv = *pi.base.bv; - Buffer & buffer = bv.buffer(); - TextMetrics const & tm = bv.textMetrics(this); - DocIterator cur = beg; - int x1 = cursorX(bv, beg.top(), beg.boundary()); - int x2 = cursorX(bv, end.top(), end.boundary()); - int y1 = bv_funcs::getPos(bv, cur, cur.boundary()).y_ - row.ascent(); - int y2 = y1 + row.height(); - - // draw the margins - if (drawOnBegMargin) { - if (isRTL(buffer, beg.paragraph())) - pi.pain.fillRectangle(x + x1, y1, tm.width() - x1, y2 - y1, Color::selection); - else - pi.pain.fillRectangle(x, y1, x1, y2 - y1, Color::selection); - } - - if (drawOnEndMargin) { - if (isRTL(buffer, beg.paragraph())) - pi.pain.fillRectangle(x, y1, x2, y2 - y1, Color::selection); - else - pi.pain.fillRectangle(x + x2, y1, tm.width() - x2, y2 - y1, Color::selection); - } - - // if we are on a boundary from the beginning, it's probably - // a RTL boundary and we jump to the other side directly as this - // segement is 0-size and confuses the logic below - if (cur.boundary()) - cur.boundary(false); - - // go through row and draw from RTL boundary to RTL boundary - while (cur < end) { - bool drawNow = false; - - // simplified cursorRight code below which does not - // descend into insets and which does not go into the - // next line. Compare the logic with the original cursorRight - - // if left of boundary -> just jump to right side - // but for RTL boundaries don't, because: abc|DDEEFFghi -> abcDDEEF|Fghi - if (cur.boundary()) { - cur.boundary(false); - } else if (isRTLBoundary(buffer, cur.paragraph(), cur.pos() + 1)) { - // in front of RTL boundary -> Stay on this side of the boundary because: - // ab|cDDEEFFghi -> abc|DDEEFFghi - ++cur.pos(); - cur.boundary(true); - drawNow = true; - } else { - // move right - ++cur.pos(); - - // line end? - if (cur.pos() == row.endpos()) - cur.boundary(true); - } - - if (x1 == -1) { - // the previous segment was just drawn, now the next starts - x1 = cursorX(bv, cur.top(), cur.boundary()); - } - - if (!(cur < end) || drawNow) { - x2 = cursorX(bv, cur.top(), cur.boundary()); - pi.pain.fillRectangle(x + 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) - x1 = -1; - } - } -} - - - bool Text::isLastRow(pit_type pit, Row const & row) const { return row.endpos() >= pars_[pit].size() diff --git a/src/Text.h b/src/Text.h index e351bd5998..d697637214 100644 --- a/src/Text.h +++ b/src/Text.h @@ -127,8 +127,6 @@ public: /// draw text (only used for insets) void draw(PainterInfo & pi, int x, int y) const; - /// draw textselection - void drawSelection(PainterInfo & pi, int x, int y) const; /// try to handle that request /// FIXME: replace Cursor with DocIterator. @@ -406,10 +404,6 @@ private: void charInserted(); /// set 'number' font property void number(Cursor & cur); - /// draw selection for a single row - void drawRowSelection(PainterInfo & pi, int x, Row const & row, - DocIterator const & beg, DocIterator const & end, - bool drawOnBegMargin, bool drawOnEndMargin) const; /// paste plain text at current cursor. /// \param str string to paste diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 81cd7c158f..8f3f993816 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -22,6 +22,7 @@ #include "Buffer.h" #include "BufferParams.h" #include "BufferView.h" +#include "bufferview_funcs.h" #include "Color.h" #include "CoordCache.h" #include "debug.h" @@ -40,6 +41,8 @@ #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include + using std::max; using std::min; using std::endl; @@ -969,6 +972,7 @@ void TextMetrics::draw(PainterInfo & pi, int x, int y) const { if (par_metrics_.empty()) return; + ParMetricsCache::const_iterator it = par_metrics_.begin(); ParMetricsCache::const_iterator const end = par_metrics_.end(); y -= it->second.ascent(); @@ -1053,6 +1057,162 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co LYXERR(Debug::PAINTING) << "." << endl; } + +// only used for inset right now. should also be used for main text +void TextMetrics::drawSelection(PainterInfo & pi, int x, int) const +{ + Cursor & cur = bv_->cursor(); + if (!cur.selection()) + return; + if (!ptr_cmp(cur.text(), text_)) + return; + + LYXERR(Debug::DEBUG) + << BOOST_CURRENT_FUNCTION + << "draw selection at " << x + << endl; + + DocIterator beg = cur.selectionBegin(); + DocIterator end = cur.selectionEnd(); + + // the selection doesn't touch the visible screen? + if (bv_funcs::status(bv_, beg) == bv_funcs::CUR_BELOW + || bv_funcs::status(bv_, end) == bv_funcs::CUR_ABOVE) + return; + + ParagraphMetrics const & pm1 = par_metrics_[beg.pit()]; + ParagraphMetrics const & pm2 = par_metrics_[end.pit()]; + Row const & row1 = pm1.getRow(beg.pos(), beg.boundary()); + Row const & row2 = pm2.getRow(end.pos(), end.boundary()); + + // clip above + int middleTop; + bool const clipAbove = + (bv_funcs::status(bv_, beg) == bv_funcs::CUR_ABOVE); + if (clipAbove) + middleTop = 0; + else + middleTop = bv_funcs::getPos(*bv_, beg, beg.boundary()).y_ + row1.descent(); + + // clip below + int middleBottom; + bool const clipBelow = + (bv_funcs::status(bv_, end) == bv_funcs::CUR_BELOW); + if (clipBelow) + middleBottom = bv_->workHeight(); + else + middleBottom = bv_funcs::getPos(*bv_, end, end.boundary()).y_ - row2.ascent(); + + // start and end in the same line? + if (!(clipAbove || clipBelow) && &row1 == &row2) + // then only draw this row's selection + drawRowSelection(pi, x, row1, beg, end, false, false); + else { + if (!clipAbove) { + // get row end + DocIterator begRowEnd = beg; + begRowEnd.pos() = row1.endpos(); + begRowEnd.boundary(true); + + // draw upper rectangle + drawRowSelection(pi, x, row1, beg, begRowEnd, false, true); + } + + if (middleTop < middleBottom) { + // draw middle rectangle + pi.pain.fillRectangle(x, middleTop, width(), middleBottom - middleTop, + Color::selection); + } + + if (!clipBelow) { + // get row begin + DocIterator endRowBeg = end; + endRowBeg.pos() = row2.pos(); + endRowBeg.boundary(false); + + // draw low rectangle + drawRowSelection(pi, x, row2, endRowBeg, end, true, false); + } + } +} + + +void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row, + DocIterator const & beg, DocIterator const & end, + bool drawOnBegMargin, bool drawOnEndMargin) const +{ + Buffer & buffer = bv_->buffer(); + DocIterator cur = beg; + int x1 = text_->cursorX(*bv_, beg.top(), beg.boundary()); + int x2 = text_->cursorX(*bv_, end.top(), end.boundary()); + int y1 = bv_funcs::getPos(*bv_, cur, cur.boundary()).y_ - row.ascent(); + int y2 = y1 + row.height(); + + // draw the margins + if (drawOnBegMargin) { + if (text_->isRTL(buffer, beg.paragraph())) + pi.pain.fillRectangle(x + x1, y1, width() - x1, y2 - y1, Color::selection); + else + pi.pain.fillRectangle(x, y1, x1, y2 - y1, Color::selection); + } + + if (drawOnEndMargin) { + if (text_->isRTL(buffer, beg.paragraph())) + pi.pain.fillRectangle(x, y1, x2, y2 - y1, Color::selection); + else + pi.pain.fillRectangle(x + x2, y1, width() - x2, y2 - y1, Color::selection); + } + + // if we are on a boundary from the beginning, it's probably + // a RTL boundary and we jump to the other side directly as this + // segement is 0-size and confuses the logic below + if (cur.boundary()) + cur.boundary(false); + + // go through row and draw from RTL boundary to RTL boundary + while (cur < end) { + bool drawNow = false; + + // simplified cursorRight code below which does not + // descend into insets and which does not go into the + // next line. Compare the logic with the original cursorRight + + // if left of boundary -> just jump to right side + // but for RTL boundaries don't, because: abc|DDEEFFghi -> abcDDEEF|Fghi + if (cur.boundary()) { + cur.boundary(false); + } else if (text_->isRTLBoundary(buffer, cur.paragraph(), cur.pos() + 1)) { + // in front of RTL boundary -> Stay on this side of the boundary because: + // ab|cDDEEFFghi -> abc|DDEEFFghi + ++cur.pos(); + cur.boundary(true); + drawNow = true; + } else { + // move right + ++cur.pos(); + + // line end? + if (cur.pos() == row.endpos()) + cur.boundary(true); + } + + if (x1 == -1) { + // the previous segment was just drawn, now the next starts + x1 = text_->cursorX(*bv_, cur.top(), cur.boundary()); + } + + if (!(cur < end) || drawNow) { + x2 = text_->cursorX(*bv_, cur.top(), cur.boundary()); + pi.pain.fillRectangle(x + 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) + x1 = -1; + } + } +} + //int Text::pos2x(pit_type pit, pos_type pos) const //{ // ParagraphMetrics const & pm = par_metrics_[pit]; diff --git a/src/TextMetrics.h b/src/TextMetrics.h index 2023a16328..f0444076f2 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -27,8 +27,9 @@ namespace lyx { class BufferView; -class Text; +class DocIterator; class MetricsInfo; +class Text; /// A map from a Text to the map of paragraphs metrics class TextMetrics @@ -78,6 +79,8 @@ public: /// void draw(PainterInfo & pi, int x, int y) const; + /// draw textselection + void drawSelection(PainterInfo & pi, int x, int y) const; void drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) const; @@ -114,6 +117,11 @@ private: pos_type const end ) const; + /// draw selection for a single row + void drawRowSelection(PainterInfo & pi, int x, Row const & row, + DocIterator const & beg, DocIterator const & end, + bool drawOnBegMargin, bool drawOnEndMargin) const; + // Temporary public: public: /// returns the column near the specified x-coordinate of the row. diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp index 03f4bcbb62..20ee632763 100644 --- a/src/insets/InsetText.cpp +++ b/src/insets/InsetText.cpp @@ -202,7 +202,7 @@ void InsetText::draw(PainterInfo & pi, int x, int y) const if (drawFrame_) pi.pain.rectangle(x, y - a, w, h, frameColor()); } - text_.drawSelection(pi, x + border_, y); + tm.drawSelection(pi, x + border_, y); tm.draw(pi, x + border_, y); } diff --git a/src/mathed/InsetMathMBox.cpp b/src/mathed/InsetMathMBox.cpp index 670165bae6..882c93b618 100644 --- a/src/mathed/InsetMathMBox.cpp +++ b/src/mathed/InsetMathMBox.cpp @@ -124,7 +124,7 @@ void InsetMathMBox::cursorPos(BufferView const & bv, void InsetMathMBox::drawSelection(PainterInfo & pi, int x, int y) const { - text_.drawSelection(pi, x, y); + pi.base.bv->textMetrics(&text_).drawSelection(pi, x, y); } -- 2.39.5