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_; }

Reply via email to