diff --git a/src/BufferView.cpp b/src/BufferView.cpp index a418509625..7ce16c4c05 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1539,8 +1539,7 @@ void BufferView::draw(frontend::Painter & pain) // FIXME: We should also distinguish DecorationUpdate to avoid text // drawing if possible. This is not possible to do easily right now // because of the single backing pixmap. - pi.full_repaint = select - || metrics_info_.update_strategy != SingleParUpdate; + pi.full_repaint = metrics_info_.update_strategy != SingleParUpdate; if (pi.full_repaint) // Clear background (if not delegated to rows) @@ -1548,20 +1547,13 @@ void BufferView::draw(frontend::Painter & pain) metrics_info_.y2 - metrics_info_.y1, buffer_.inset().backgroundColor()); - TextMetrics const & tm = text_metrics_[&text]; - - if (select) - tm.drawSelection(pi, 0, 0); - - int yy = metrics_info_.y1; - // draw contents LYXERR(Debug::PAINTING) << "\t\t*** START DRAWING ***" << endl; - for (pit_type pit = metrics_info_.p1; pit <= metrics_info_.p2; ++pit) { - ParagraphMetrics const & pm = tm.parMetrics(pit); - yy += pm.ascent(); - tm.drawParagraph(pi, pit, 0, yy); - yy += pm.descent(); - } + TextMetrics const & tm = text_metrics_[&text]; + if (!pi.full_repaint) + tm.drawParagraph(pi, metrics_info_.p1, 0, + metrics_info_.y1 + tm.parMetrics(metrics_info_.p1).ascent()); + else + tm.draw(pi, 0, metrics_info_.y1 + tm.parMetrics(metrics_info_.p1).ascent()); LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING ***" << endl; // and grey out above (should not happen later) diff --git a/src/Row.cpp b/src/Row.cpp index 3bf393b7ce..6f1a31c078 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -25,13 +25,13 @@ namespace lyx { Row::Row() : changed_(false), crc_(0), pos_(0), end_(0), separator(0), hfill(0), - label_hfill(0), x(0) + label_hfill(0), x(0), sel_beg(-1), sel_end(-1) {} Row::Row(pos_type pos) : changed_(false), crc_(0), pos_(pos), end_(0), separator(0), hfill(0), - label_hfill(0), x(0) + label_hfill(0), x(0), sel_beg(-1), sel_end(-1) {} @@ -61,6 +61,34 @@ void Row::endpos(pos_type p) } +void Row::setSelection(pos_type beg, pos_type end) +{ + pos_type sel_beg_b = sel_beg; + if (pos_ >= beg && pos_ <= end) + sel_beg = pos_; + else if (beg > pos_ && beg <= end_) + sel_beg = beg; + else + sel_beg = -1; + + pos_type sel_end_b = sel_end; + if (end_ >= beg && end_ <= end) + sel_end = end_; + else if (end < end_ && end >= pos_) + sel_end = end; + else + sel_end = -1; +/* + && ((rit->pos() >= beg.pos() && rit->pos() <= end.pos()) + || (rit->endpos() >= beg.pos() && rit->endpos() <= end.pos()) + || (beg.pos() >= rit->pos() && beg.pos() <= rit->endpos()) + || (end.pos() >= rit->pos() && end.pos() <= rit->endpos())); +*/ + changed_ |= sel_beg_b != sel_beg; + changed_ |= sel_end_b != sel_end; +} + + void Row::dump(const char * s) const { lyxerr << s << " pos: " << pos_ << " end: " << end_ diff --git a/src/Row.h b/src/Row.h index 2838f48e74..f013fb49db 100644 --- a/src/Row.h +++ b/src/Row.h @@ -39,6 +39,9 @@ public: void setChanged(bool c) { changed_ = c; } /// void setCrc(size_type crc); + /// + void setSelection(pos_type sel_beg, pos_type sel_end); + /// void pos(pos_type p); /// @@ -71,6 +74,11 @@ public: double label_hfill; /// the x position of the row double x; + /// + pos_type sel_beg; + /// + pos_type sel_end; + private: /// has the Row appearance changed since last drawing? diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 3acc85ad7b..2db02ecbf2 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -361,6 +361,28 @@ bool TextMetrics::redoParagraph(pit_type const pit) changed |= (old_dim != dim); } + Cursor const & cur = bv_->cursor(); + DocIterator sel_beg = cur.selectionBegin(); + DocIterator sel_end = cur.selectionEnd(); + bool selection = cur.selection() + // This is out text. + && cur.text() == text_ + // if the anchor is outside, this is not our selection + && cur.anchor().text() == text_ + && pit >= sel_beg.pit() && pit <= sel_end.pit(); + + // We care only about visible selection. + if (selection) { + if (pit != sel_beg.pit()) { + sel_beg.pit() = pit; + sel_beg.pos() = 0; + } + if (pit != sel_end.pit()) { + sel_end.pit() = pit; + sel_end.pos() = sel_end.lastpos(); + } + } + par.setBeginOfBody(); pos_type first = 0; size_t row_index = 0; @@ -383,6 +405,10 @@ bool TextMetrics::redoParagraph(pit_type const pit) row.setChanged(false); row.pos(first); row.endpos(end); + if (selection) + row.setSelection(sel_beg.pos(), sel_end.pos()); + else + row.setSelection(-1, -1); row.setDimension(dim); computeRowMetrics(pit, row); pm.computeRowSignature(row, bparams); @@ -1094,8 +1120,12 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit, pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const { - ParagraphMetrics const & pm = par_metrics_[pit]; - BOOST_ASSERT(!pm.rows().empty()); + // We play safe and use parMetrics(pit) to make sure the + // ParagraphMetrics will be redone and OK to use if needed. + // Otherwise we would use an empty ParagraphMetrics in + // upDownInText() while in selection mode. + ParagraphMetrics const & pm = parMetrics(pit); + BOOST_ASSERT(row < int(pm.rows().size())); bool bound = false; Row const & r = pm.rows()[row]; @@ -1772,13 +1802,18 @@ void TextMetrics::draw(PainterInfo & pi, int x, int y) const if (par_metrics_.empty()) return; + CoordCache::InnerParPosCache & ppcache = bv_->coordCache().parPos()[text_]; + ParMetricsCache::const_iterator it = par_metrics_.begin(); - ParMetricsCache::const_iterator const end = par_metrics_.end(); + ParMetricsCache::const_iterator const pm_end = par_metrics_.end(); y -= it->second.ascent(); - for (; it != end; ++it) { + for (; it != pm_end; ++it) { ParagraphMetrics const & pmi = it->second; y += pmi.ascent(); - drawParagraph(pi, it->first, x, y); + pit_type const pit = it->first; + // Save the paragraph position in the cache. + ppcache[pit] = Point(x, y); + drawParagraph(pi, pit, x, y); y += pmi.descent(); } } @@ -1789,8 +1824,6 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co // lyxerr << " paintPar: pit: " << pit << " at y: " << y << endl; int const ww = bv_->workHeight(); - bv_->coordCache().parPos()[text_][pit] = Point(x, y); - ParagraphMetrics const & pm = par_metrics_[pit]; if (pm.rows().empty()) return; @@ -1813,7 +1846,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co // Row signature; has row changed since last paint? bool row_has_changed = rit->changed(); - if (!pi.full_repaint && !row_has_changed) { + bool row_selection = rit->sel_beg != -1 && rit->sel_end != -1; + + if (!row_selection && !pi.full_repaint && !row_has_changed) { // Paint the only the insets if the text itself is // unchanged. rp.paintOnlyInsets(); @@ -1825,11 +1860,25 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co // changed. // Clear background of this row // (if paragraph background was not cleared) - if (!pi.full_repaint && row_has_changed) { + if (row_selection || (!pi.full_repaint && row_has_changed)) { pi.pain.fillRectangle(x, y - rit->ascent(), width(), rit->height(), Color_color(Color::color(pi.background_color))); } + if (row_selection) { + lyxerr << "row selected" << endl; + DocIterator beg = bv_->cursor().selectionBegin(); + DocIterator end = bv_->cursor().selectionEnd(); + beg.pit() = pit; + beg.pos() = rit->sel_beg; + if (pit == end.pit()) { + end.pos() = rit->sel_end; + } else { + end.pit() = pit + 1; + end.pos() = 0; + } + drawSelection(pi, beg, end, x); + } // Instrumentation for testing row cache (see also // 12 lines lower): @@ -1866,40 +1915,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co // only used for inset right now. should also be used for main text -void TextMetrics::drawSelection(PainterInfo & pi, int x, int) const +void TextMetrics::drawSelection(PainterInfo & pi, + DocIterator const & beg, DocIterator const & end, int x) const { - Cursor & cur = bv_->cursor(); - if (!cur.selection()) - return; - if (!ptr_cmp(cur.text(), text_)) - return; - - //if the anchor is outside, this is not our selection - if (!ptr_cmp(cur.anchor().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; - - if (beg.pit() < par_metrics_.begin()->first) { - beg.pit() = par_metrics_.begin()->first; - beg.pos() = 0; - } - if (end.pit() > par_metrics_.rbegin()->first) { - end.pit() = par_metrics_.rbegin()->first; - end.pos() = end.lastpos(); - } - ParagraphMetrics const & pm1 = par_metrics_[beg.pit()]; ParagraphMetrics const & pm2 = par_metrics_[end.pit()]; Row const & row1 = pm1.getRow(beg.pos(), beg.boundary()); diff --git a/src/TextMetrics.h b/src/TextMetrics.h index d850074310..0057e837e3 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -42,6 +42,7 @@ public: TextMetrics(BufferView *, Text *); /// ParagraphMetrics const & parMetrics(pit_type) const; + /// Dimension const & dimension() const; Dimension const & dimension(); @@ -107,8 +108,6 @@ 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; @@ -116,6 +115,13 @@ private: /// ParagraphMetrics & parMetrics(pit_type, bool redo_paragraph); + /// draw textselection. + /// FIXME: simplify to just to single row painting. + void drawSelection(PainterInfo & pi, + DocIterator const & beg, ///< selection begin. + DocIterator const & end, ///< selection end. + int x) const; + /// the minimum space a manual label needs on the screen in pixels int labelFill(pit_type const pit, Row const & row) const; diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp index 93de904c43..a021235664 100644 --- a/src/insets/InsetText.cpp +++ b/src/insets/InsetText.cpp @@ -195,7 +195,6 @@ void InsetText::draw(PainterInfo & pi, int x, int y) const if (drawFrame_) pi.pain.rectangle(x, y - a, w, h, frameColor()); } - 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 e212d2f4fb..e6df5b41e2 100644 --- a/src/mathed/InsetMathMBox.cpp +++ b/src/mathed/InsetMathMBox.cpp @@ -122,10 +122,4 @@ void InsetMathMBox::cursorPos(BufferView const & bv, } -void InsetMathMBox::drawSelection(PainterInfo & pi, int x, int y) const -{ - pi.base.bv->textMetrics(&text_).drawSelection(pi, x, y); -} - - } // namespace lyx diff --git a/src/mathed/InsetMathMBox.h b/src/mathed/InsetMathMBox.h index 437edf0cb5..4ca1502dc0 100644 --- a/src/mathed/InsetMathMBox.h +++ b/src/mathed/InsetMathMBox.h @@ -38,8 +38,6 @@ public: /// draw according to cached metrics void draw(PainterInfo &, int x, int y) const; /// - void drawSelection(PainterInfo & pi, int x, int y) const; - /// bool inMathed() const { return false; } /// bool isActive() const { return true; }