Move selection painting closer to row painting. Single row painting is now possible for selection.

* Row:
- setSelection(): set selection begin and end for this row.
- sel_beg, sel_end: new public members.

* BufferView::draw()
- do not trigger a full repaint for selection.
- use TextMetrics::draw() instead of hand calling TextMetrics::drawParagraph().

* InsetText::draw(): don't call TextMetrics::drawSelection().

* InsetMathMBox::drawSelection(): remove.

* TextMetrics:
- drawSelection(): simplify a bit. Now private.
- redoParagraph(): memorize Row selection status.
- x2pos(): fix crash when selecting with PageDown.
- draw(): fill-in the ParPos cache before everything else and not in drawParagraph().
- drawParagraph(): take care of row selection painting.







git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@20066 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-09-05 13:04:05 +00:00
parent 9044e9d68a
commit eed6514dd0
8 changed files with 113 additions and 70 deletions

View File

@ -1539,8 +1539,7 @@ void BufferView::draw(frontend::Painter & pain)
// FIXME: We should also distinguish DecorationUpdate to avoid text // FIXME: We should also distinguish DecorationUpdate to avoid text
// drawing if possible. This is not possible to do easily right now // drawing if possible. This is not possible to do easily right now
// because of the single backing pixmap. // because of the single backing pixmap.
pi.full_repaint = select pi.full_repaint = metrics_info_.update_strategy != SingleParUpdate;
|| metrics_info_.update_strategy != SingleParUpdate;
if (pi.full_repaint) if (pi.full_repaint)
// Clear background (if not delegated to rows) // Clear background (if not delegated to rows)
@ -1548,20 +1547,13 @@ void BufferView::draw(frontend::Painter & pain)
metrics_info_.y2 - metrics_info_.y1, metrics_info_.y2 - metrics_info_.y1,
buffer_.inset().backgroundColor()); 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; LYXERR(Debug::PAINTING) << "\t\t*** START DRAWING ***" << endl;
for (pit_type pit = metrics_info_.p1; pit <= metrics_info_.p2; ++pit) { TextMetrics const & tm = text_metrics_[&text];
ParagraphMetrics const & pm = tm.parMetrics(pit); if (!pi.full_repaint)
yy += pm.ascent(); tm.drawParagraph(pi, metrics_info_.p1, 0,
tm.drawParagraph(pi, pit, 0, yy); metrics_info_.y1 + tm.parMetrics(metrics_info_.p1).ascent());
yy += pm.descent(); else
} tm.draw(pi, 0, metrics_info_.y1 + tm.parMetrics(metrics_info_.p1).ascent());
LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING ***" << endl; LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING ***" << endl;
// and grey out above (should not happen later) // and grey out above (should not happen later)

View File

@ -25,13 +25,13 @@ namespace lyx {
Row::Row() Row::Row()
: changed_(false), crc_(0), pos_(0), end_(0), separator(0), hfill(0), : 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) Row::Row(pos_type pos)
: changed_(false), crc_(0), pos_(pos), end_(0), separator(0), hfill(0), : 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 void Row::dump(const char * s) const
{ {
lyxerr << s << " pos: " << pos_ << " end: " << end_ lyxerr << s << " pos: " << pos_ << " end: " << end_

View File

@ -39,6 +39,9 @@ public:
void setChanged(bool c) { changed_ = c; } void setChanged(bool c) { changed_ = c; }
/// ///
void setCrc(size_type crc); void setCrc(size_type crc);
///
void setSelection(pos_type sel_beg, pos_type sel_end);
/// ///
void pos(pos_type p); void pos(pos_type p);
/// ///
@ -71,6 +74,11 @@ public:
double label_hfill; double label_hfill;
/// the x position of the row /// the x position of the row
double x; double x;
///
pos_type sel_beg;
///
pos_type sel_end;
private: private:
/// has the Row appearance changed since last drawing? /// has the Row appearance changed since last drawing?

View File

@ -361,6 +361,28 @@ bool TextMetrics::redoParagraph(pit_type const pit)
changed |= (old_dim != dim); 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(); par.setBeginOfBody();
pos_type first = 0; pos_type first = 0;
size_t row_index = 0; size_t row_index = 0;
@ -383,6 +405,10 @@ bool TextMetrics::redoParagraph(pit_type const pit)
row.setChanged(false); row.setChanged(false);
row.pos(first); row.pos(first);
row.endpos(end); row.endpos(end);
if (selection)
row.setSelection(sel_beg.pos(), sel_end.pos());
else
row.setSelection(-1, -1);
row.setDimension(dim); row.setDimension(dim);
computeRowMetrics(pit, row); computeRowMetrics(pit, row);
pm.computeRowSignature(row, bparams); 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 pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
{ {
ParagraphMetrics const & pm = par_metrics_[pit]; // We play safe and use parMetrics(pit) to make sure the
BOOST_ASSERT(!pm.rows().empty()); // 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())); BOOST_ASSERT(row < int(pm.rows().size()));
bool bound = false; bool bound = false;
Row const & r = pm.rows()[row]; Row const & r = pm.rows()[row];
@ -1772,13 +1802,18 @@ void TextMetrics::draw(PainterInfo & pi, int x, int y) const
if (par_metrics_.empty()) if (par_metrics_.empty())
return; return;
CoordCache::InnerParPosCache & ppcache = bv_->coordCache().parPos()[text_];
ParMetricsCache::const_iterator it = par_metrics_.begin(); 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(); y -= it->second.ascent();
for (; it != end; ++it) { for (; it != pm_end; ++it) {
ParagraphMetrics const & pmi = it->second; ParagraphMetrics const & pmi = it->second;
y += pmi.ascent(); 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(); 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; // lyxerr << " paintPar: pit: " << pit << " at y: " << y << endl;
int const ww = bv_->workHeight(); int const ww = bv_->workHeight();
bv_->coordCache().parPos()[text_][pit] = Point(x, y);
ParagraphMetrics const & pm = par_metrics_[pit]; ParagraphMetrics const & pm = par_metrics_[pit];
if (pm.rows().empty()) if (pm.rows().empty())
return; 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? // Row signature; has row changed since last paint?
bool row_has_changed = rit->changed(); 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 // Paint the only the insets if the text itself is
// unchanged. // unchanged.
rp.paintOnlyInsets(); rp.paintOnlyInsets();
@ -1825,11 +1860,25 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
// changed. // changed.
// Clear background of this row // Clear background of this row
// (if paragraph background was not cleared) // (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(), pi.pain.fillRectangle(x, y - rit->ascent(),
width(), rit->height(), width(), rit->height(),
Color_color(Color::color(pi.background_color))); 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 // Instrumentation for testing row cache (see also
// 12 lines lower): // 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 // 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 & pm1 = par_metrics_[beg.pit()];
ParagraphMetrics const & pm2 = par_metrics_[end.pit()]; ParagraphMetrics const & pm2 = par_metrics_[end.pit()];
Row const & row1 = pm1.getRow(beg.pos(), beg.boundary()); Row const & row1 = pm1.getRow(beg.pos(), beg.boundary());

View File

@ -42,6 +42,7 @@ public:
TextMetrics(BufferView *, Text *); TextMetrics(BufferView *, Text *);
/// ///
ParagraphMetrics const & parMetrics(pit_type) const; ParagraphMetrics const & parMetrics(pit_type) const;
/// ///
Dimension const & dimension() const; Dimension const & dimension() const;
Dimension const & dimension(); Dimension const & dimension();
@ -107,8 +108,6 @@ public:
/// ///
void draw(PainterInfo & pi, int x, int y) const; 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; void drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) const;
@ -116,6 +115,13 @@ private:
/// ///
ParagraphMetrics & parMetrics(pit_type, bool redo_paragraph); 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 /// the minimum space a manual label needs on the screen in pixels
int labelFill(pit_type const pit, Row const & row) const; int labelFill(pit_type const pit, Row const & row) const;

View File

@ -195,7 +195,6 @@ void InsetText::draw(PainterInfo & pi, int x, int y) const
if (drawFrame_) if (drawFrame_)
pi.pain.rectangle(x, y - a, w, h, frameColor()); pi.pain.rectangle(x, y - a, w, h, frameColor());
} }
tm.drawSelection(pi, x + border_, y);
tm.draw(pi, x + border_, y); tm.draw(pi, x + border_, y);
} }

View File

@ -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 } // namespace lyx

View File

@ -38,8 +38,6 @@ public:
/// draw according to cached metrics /// draw according to cached metrics
void draw(PainterInfo &, int x, int y) const; void draw(PainterInfo &, int x, int y) const;
/// ///
void drawSelection(PainterInfo & pi, int x, int y) const;
///
bool inMathed() const { return false; } bool inMathed() const { return false; }
/// ///
bool isActive() const { return true; } bool isActive() const { return true; }