Abdel,
I took the liberty to change the drawParagraph function in
TextMetrics.cpp a bit. This because, after you asked me to use
meaningfull names for the variables, I tried to understand the other
names in the function and I didn't succeed. I felt that variables
shouldn't change their role during the function and that the boundary
member shouldn't be used differently than how it is documented.
Besides, I improved the logic of drawing the margins further, such that
I cannot find any drawing errors left.
Here are some explanations:
+ CursorSlice par_slice = cur.top();
+ par_slice.pit() = pit;
+
+ // We store the begin and end pos of the selection relative to this par
+ pos_type sel_beg_par_pos = -1;
+ pos_type sel_end_par_pos = -1;
// 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();
- }
+ sel_beg_par_pos = sel_beg.pit() == pit ? sel_beg.pos() : 0;
+ sel_end_par_pos = sel_end.pit() == pit ?
+ sel_end.pos() : par_slice.lastpos();
}
1. Sel_beg and sel_end were first used to indicate the current
selection, then they were adapted to represent the selection
clipped to the current paragraph (without comment). I think
it is better just to make two variables for that and to let
sel_beg and sel_end keep the same role throughout the function.
- DocIterator beg = bv_->cursor().selectionBegin();
- DocIterator end = bv_->cursor().selectionEnd();
// FIXME (not here): pit is not updated when extending
// a selection to a new row with cursor right/left
- bool const beg_margin = beg.pit() < pit;
- bool const end_margin = end.pit() > pit;
- beg.pit() = pit;
- beg.pos() = row.sel_beg;
- end.pit() = pit;
- end.pos() = row.sel_end;
- if (end.pos() == row.endpos()) {
- // selection goes till the end of the row.
- end.boundary(true);
2. The same as above, beg and end are first used as the begin and end of
the selection. Then, they are clipped to the row. Moreover, the
boundary member is misused to carry information that says nothing
about whether the cursor is after i-1 or before i.
As this is just administration I moved it into drawSelection().
// FIXME (not here): pit is not updated when extending // a selection to
a new row with cursor right/left
3. I don't know whether this FIXME is still necessary. I didn't found any
problems with it.
+ bool const begin_boundary = beg.pos() >= row.endpos();
4. This is necessary to prevent painting errors.
Vincent
======================================================================
Index: src/TextMetrics.cpp
===================================================================
--- src/TextMetrics.cpp (revision 26377)
+++ src/TextMetrics.cpp (working copy)
@@ -1971,16 +1971,17 @@
&& cur.anchor().text() == text_
&& pit >= sel_beg.pit() && pit <= sel_end.pit();
+ CursorSlice par_slice = cur.top();
+ par_slice.pit() = pit;
+
+ // We store the begin and end pos of the selection relative to this par
+ pos_type sel_beg_par_pos = -1;
+ pos_type sel_end_par_pos = -1;
// 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();
- }
+ sel_beg_par_pos = sel_beg.pit() == pit ? sel_beg.pos() : 0;
+ sel_end_par_pos = sel_end.pit() == pit ?
+ sel_end.pos() : par_slice.lastpos();
}
for (size_t i = 0; i != nrows; ++i) {
@@ -1995,13 +1996,11 @@
pi.pain.setDrawingEnabled(inside && original_drawing_state);
RowPainter rp(pi, *text_, pit, row, bidi, x, y);
- if (selection)
- row.setSelection(sel_beg.pos(), sel_end.pos());
- else
- row.setSelection(-1, -1);
-
+ row.setSelection(sel_beg_par_pos, sel_end_par_pos);
+
// Row signature; has row changed since last paint?
- row.setCrc(pm.computeRowSignature(row, bparams));
+ row.setCrc(pm.computeRowSignature(row, bparams,
+ sel_beg, sel_end, pit));
bool row_has_changed = row.changed();
// Don't paint the row if a full repaint has not been requested
@@ -2023,21 +2022,51 @@
bool row_selection = row.sel_beg != -1 && row.sel_end != -1;
if (row_selection) {
- DocIterator beg = bv_->cursor().selectionBegin();
- DocIterator end = bv_->cursor().selectionEnd();
// FIXME (not here): pit is not updated when extending
// a selection to a new row with cursor right/left
- bool const beg_margin = beg.pit() < pit;
- bool const end_margin = end.pit() > pit;
- beg.pit() = pit;
- beg.pos() = row.sel_beg;
- end.pit() = pit;
- end.pos() = row.sel_end;
- if (end.pos() == row.endpos()) {
- // selection goes till the end of the row.
- end.boundary(true);
+
+ bool end_margin = false;
+ // Is the end of the row part of the selection ?
+ if (row.sel_end == row.endpos()) {
+ if (row.sel_end == par_slice.lastpos())
+ // The margin between paragraphs is
only drawn if the
+ // selection extends into the next
paragraph.
+ end_margin = sel_end.pit() > pit ;
+ else if (sel_end_par_pos == sel_beg_par_pos)
+ // This is a special case in which the
space between after
+ // pos i-1 and before pos i is
selected, i.e. the margins
+ // (see DocIterator::boundary_).
+ end_margin = sel_beg.boundary() &&
!sel_end.boundary();
+ else if (sel_end_par_pos == row.sel_end)
+ // If the selection ends around the end
margin, it is only
+ // drawn if the cursor after the
margins.
+ end_margin = !sel_end.boundary();
+ else if (sel_beg_par_pos == row.sel_end)
+ // If the selection begins around the
end margin, it is
+ // only drawn if the cursor is before
the margins.
+ end_margin = sel_beg.boundary();
+ else
+ end_margin = true;
}
- drawRowSelection(pi, x, row, beg, end, beg_margin,
end_margin);
+
+ // This code for the begin margin follows the same
logic as for
+ // the end_margin above.
+ bool beg_margin = false;
+ // Is the beginning of the row part of the selection ?
+ if (row.sel_beg == row.pos()) {
+ if (row.pos() == 0)
+ beg_margin = sel_beg.pit() < pit;
+ else if (sel_end_par_pos == sel_beg_par_pos)
+ beg_margin = sel_beg.boundary() &&
!sel_end.boundary();
+ else if (sel_end_par_pos == row.pos())
+ beg_margin = !sel_end.boundary();
+ else if (sel_beg_par_pos == row.pos())
+ beg_margin = sel_beg.boundary();
+ else
+ beg_margin = true;
+ }
+
+ drawRowSelection(pi, x, row, cur, pit, beg_margin,
end_margin);
}
// Instrumentation for testing row cache (see also
@@ -2076,13 +2105,25 @@
void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row,
- DocIterator const & beg, DocIterator const & end,
+ Cursor const & curs, pit_type pit,
bool drawOnBegMargin, bool drawOnEndMargin) const
{
+ DocIterator beg = curs.selectionBegin();
+ beg.pit() = pit;
+ beg.pos() = row.sel_beg;
+
+ DocIterator end = curs.selectionEnd();
+ end.pit() = pit;
+ end.pos() = row.sel_end;
+
+ bool const begin_boundary = beg.pos() >= row.endpos();
+ bool const end_boundary = row.sel_end == row.endpos();
+
Buffer & buffer = bv_->buffer();
DocIterator cur = beg;
- int x1 = cursorX(beg.top(), beg.boundary());
- int x2 = cursorX(end.top(), end.boundary());
+ cur.boundary(begin_boundary);
+ int x1 = cursorX(beg.top(), begin_boundary);
+ int x2 = cursorX(end.top(), end_boundary);
int y1 = bv_->getPos(cur, cur.boundary()).y_ - row.ascent();
int y2 = y1 + row.height();
Index: src/TextMetrics.h
===================================================================
--- src/TextMetrics.h (revision 26377)
+++ src/TextMetrics.h (working copy)
@@ -160,7 +160,7 @@
/// draw selection for a single row
void drawRowSelection(PainterInfo & pi, int x, Row const & row,
- DocIterator const & beg, DocIterator const & end,
+ Cursor const & cur, pit_type pit,
bool drawOnBegMargin, bool drawOnEndMargin) const;
// Temporary public:
Index: src/ParagraphMetrics.cpp
===================================================================
--- src/ParagraphMetrics.cpp (revision 26377)
+++ src/ParagraphMetrics.cpp (working copy)
@@ -88,25 +88,55 @@
size_t ParagraphMetrics::computeRowSignature(Row const & row,
- BufferParams const & bparams) const
+ BufferParams const & bparams, DocIterator const & sel_beg,
+ DocIterator const & sel_end, pit_type pit) const
{
boost::crc_32_type crc;
for (pos_type i = row.pos(); i < row.endpos(); ++i) {
- char_type const b[] = { par_->getChar(i) };
- crc.process_bytes(b, sizeof(char_type));
+ char_type const b = { par_->getChar(i) };
+ crc.process_bytes(&b, sizeof(char_type));
if (bparams.trackChanges) {
Change change = par_->lookupChange(i);
- char_type const b[] = { change.type };
+ char_type const b = { change.type };
// 1 byte is enough to encode Change::Type
- crc.process_bytes(b, 1);
+ crc.process_bytes(&b, 1);
}
}
Dimension const & d = row.dimension();
- char_type const b[] = { row.sel_beg, row.sel_end, d.wid, d.asc, d.des};
+ char_type const b[] = { row.sel_beg, row.sel_end, d.wid, d.asc, d.des };
// Each of the variable to process is 4 bytes: 4x5 = 20
crc.process_bytes(b, 20);
+ // To decide whether the end and begin margins need to be painted, we
+ // need to monitor some stuff.
+ char_type bb = 0;
+
+ // Is the beginning of the selection also at the beginning of the
paragraph
+ // but still inside this paragraph ?
+ if (row.sel_beg == 0 && sel_beg.pit() == pit)
+ bb += 1;
+
+ // Is the end of the selection also at the end of the paragraph but
still
+ // inside the paragraph ?
+ if (row.sel_end == par_->size() && sel_end.pit() == pit)
+ bb += 2;
+
+ // If the end or begin of the row is selected, monitor the boundary and
+ // whether the selection continues on the next or previous pos.
+ if (row.sel_end == row.endpos() || row.sel_beg == row.pos()) {
+ if (sel_end.pos() == row.endpos())
+ bb += 4;
+ if (sel_beg.pos() == row.pos())
+ bb += 8;
+ if (sel_end.boundary())
+ bb += 16;
+ if (sel_beg.boundary())
+ bb += 32;
+ }
+
+ crc.process_bytes(&bb, 1);
+
return crc.checksum();
}
Index: src/ParagraphMetrics.h
===================================================================
--- src/ParagraphMetrics.h (revision 26377)
+++ src/ParagraphMetrics.h (working copy)
@@ -35,6 +35,7 @@
class Buffer;
class BufferView;
class BufferParams;
+class DocIterator;
class Font;
class Inset;
class Paragraph;
@@ -88,7 +89,9 @@
bool hfillExpansion(Row const & row, pos_type pos) const;
///
- size_t computeRowSignature(Row const &, BufferParams const & bparams)
const;
+ size_t computeRowSignature(Row const &, BufferParams const & bparams,
+ DocIterator const & sel_beg, DocIterator const & sel_end,
+ pit_type pit) const;
///
int position() const { return position_; }