Transfer Text::drawSelection() to TextMetrics.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19940 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Abdelrazak Younes 2007-08-31 10:05:12 +00:00
parent 44e4909aba
commit 2bff0157b6
7 changed files with 172 additions and 173 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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 <boost/current_function.hpp>
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];

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}