]> git.lyx.org Git - lyx.git/commitdiff
Patch by Vincent that solves a number of problems related to the painting of a selection:
authorAbdelrazak Younes <younes@lyx.org>
Sun, 14 Sep 2008 14:32:40 +0000 (14:32 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Sun, 14 Sep 2008 14:32:40 +0000 (14:32 +0000)
1. When a listing is inserted in a bit of text, the line above the listing is not drawn over the full width like it is done for lines above other insets. This is because InsetListing has a AlignLeft alignment. Now, if you start selecting downwards with the mouse in this empty area, strange selection drawings appear (see attachment).
This is caused by the fact that starting your selection at such a place, causes beg.boundary() to be true in TextMetrics::drawRowSelection(..). This is correct, but this value is true for _all_ selected lines. Now, the selection acts as if it is RTL text. Therefore, just like for end.boundary, this value needs to be reset for every line.
2. Starting your selection in an end margin often causes the selection in this end margin to be painted later. This is because when starting your selection in an end margin, you may have set a (possible empty) selection before really selecting the end margin. The problem is that the checksum (computed later) is the same for this empty selection and for the end margin selection. Therfore, we need a call to cur.setSelection() before evaluating cur.selection().

3. In the following two lines, it is assumed that there is only an end margin to be painted if the selection extends to the next paragraph. This is not true for the above described case of an AlignLeft Inset. Then, the margin has also be drawn within a paragraph

4. The end and begin margins are only painted when the selection extends into the following or previous paragraph. This difference is not resembled in the checksum if you first select a row completely and then procede to the next or previous paragraph as the selection remains at the end of a row. This also holds for the AlignLeft case. Therefore I added a term to the checksum to monitor whether the end and begin margins need to be drawn.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@26399 a592a061-630c-0410-9148-cb99ea01b6c8

src/ParagraphMetrics.cpp
src/Row.cpp
src/Row.h
src/TextMetrics.cpp
src/TextMetrics.h

index 801642e52576bfe9a78922797944d0d0f1f2200c..1e4410644c4c67ab22e1e096af5d0b307b9c79b1 100644 (file)
@@ -103,9 +103,10 @@ size_t ParagraphMetrics::computeRowSignature(Row const & row,
        }
 
        Dimension const & d = row.dimension();
-       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);
+       char_type const b[] = { row.sel_beg, row.sel_end, 
+               row.left_margin_sel, row.right_margin_sel, d.wid, d.asc, d.des};
+       // Each of the variable to process is 4 bytes: 4x7 = 28
+       crc.process_bytes(b, 28);
 
        return crc.checksum();
 }
index 975940310c41b346b90342597a8c907b81190e34..8c8383b24f94af61fe9d73d1a307aaa2cf9b8870 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "Row.h"
 
+#include "DocIterator.h"
+
 #include "support/debug.h"
 
 
@@ -26,13 +28,15 @@ namespace lyx {
 
 Row::Row()
        : separator(0), label_hfill(0), x(0),
-       sel_beg(-1), sel_end(-1), changed_(false), crc_(0), pos_(0), end_(0)
+       sel_beg(-1), sel_end(-1), changed_(false), crc_(0), 
+       pos_(0), end_(0), left_margin_sel(false), right_margin_sel(false)
 {}
 
 
 Row::Row(pos_type pos)
        : separator(0), label_hfill(0), x(0),
-       sel_beg(-1), sel_end(-1), changed_(false), crc_(0), pos_(pos), end_(0)
+       sel_beg(-1), sel_end(-1), changed_(false), crc_(0), 
+       pos_(0), end_(0), left_margin_sel(false), right_margin_sel(false)
 {}
 
 
@@ -61,6 +65,46 @@ void Row::endpos(pos_type p)
 }
 
 
+bool Row::isMarginSelected(bool margin_begin, DocIterator const & beg, 
+                                                                DocIterator const & end) const
+{
+       pos_type const sel_pos = margin_begin ? sel_beg : sel_end;
+       pos_type const margin_pos = margin_begin ? pos_ : end_;
+
+       // Is the chosen margin selected ?
+       if (sel_pos == margin_pos) {
+               if (beg.pos() == end.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_).
+                       return beg.boundary() && !end.boundary();
+               else if (end.pos() == margin_pos)
+                       // If the selection ends around the margin, it is only
+                       // drawn if the cursor is after the margin.
+                       return !end.boundary();
+               else if (beg.pos() == margin_pos)
+                       // If the selection begins around the margin, it is 
+                       // only drawn if the cursor is before the margin.
+                       return beg.boundary();
+               else 
+                       return true;
+       }
+       return false;
+}
+
+
+void Row::setSelectionAndMargins(DocIterator const & beg, 
+                                                                DocIterator const & end) const
+{
+       setSelection(beg.pos(), end.pos());
+       
+       if (selection()) {
+               right_margin_sel = isMarginSelected(false, beg, end);
+               left_margin_sel = isMarginSelected(true, beg, end);
+       }
+}
+
+
 void Row::setSelection(pos_type beg, pos_type end) const
 {
        if (pos_ >= beg && pos_ <= end)
@@ -79,6 +123,12 @@ void Row::setSelection(pos_type beg, pos_type end) const
 }
 
 
+bool Row::selection() const
+{
+       return sel_beg != -1 && sel_end != -1;
+}
+
+
 void Row::dump(char const * s) const
 {
        LYXERR0(s << " pos: " << pos_ << " end: " << end_
index a3afad4c1164a3f646f36f0753e8615844561194..055608bc2e0c87c04a9e94a240e38999111abc67 100644 (file)
--- a/src/Row.h
+++ b/src/Row.h
@@ -22,6 +22,8 @@
 
 namespace lyx {
 
+class DocIterator;
+
 /**
  * An on-screen row of text. A paragraph is broken into a
  * RowList for display. Each Row contains position pointers
@@ -45,7 +47,13 @@ public:
          * time.
          */
        void setSelection(pos_type sel_beg, pos_type sel_end) const;
-
+       ///
+       bool selection() const;
+       /// Set the selection begin and end and whether the margin begin and end
+       /// are selected.
+       void setSelectionAndMargins(DocIterator const & beg, 
+               DocIterator const & end) const;
+       
        ///
        void pos(pos_type p);
        ///
@@ -80,7 +88,21 @@ public:
        mutable pos_type sel_beg;
        ///
        mutable pos_type sel_end;
+       ///
+       mutable bool left_margin_sel;
+       ///
+       mutable bool right_margin_sel;
+
 private:
+       /// Decides whether the margin is selected.
+       /**
+         * \param margin_begin
+         * \param beg
+         * \param end
+         */
+       bool isMarginSelected(bool margin_begin, DocIterator const & beg, 
+               DocIterator const & end) const;
+
        /// has the Row appearance changed since last drawing?
        mutable bool changed_;
        /// CRC of row contents.
index 84d268afb4f82e964b369999d29ff5615f0f8a09..cc25afb755fcc698c55d45b850ed3af15e6d8db7 100644 (file)
@@ -1986,15 +1986,19 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                && cur.anchor().text() == text_
                && pit >= sel_beg.pit() && pit <= sel_end.pit();
 
+       // We store the begin and end pos of the selection relative to this par
+       DocIterator sel_beg_par = cur.selectionBegin();
+       DocIterator sel_end_par = cur.selectionEnd();
+       
        // We care only about visible selection.
        if (selection) {
                if (pit != sel_beg.pit()) {
-                       sel_beg.pit() = pit;
-                       sel_beg.pos() = 0;
+                       sel_beg_par.pit() = pit;
+                       sel_beg_par.pos() = 0;
                }
                if (pit != sel_end.pit()) {
-                       sel_end.pit() = pit;
-                       sel_end.pos() = sel_end.lastpos();
+                       sel_end_par.pit() = pit;
+                       sel_end_par.pos() = sel_end_par.lastpos();
                }
        }
 
@@ -2011,9 +2015,18 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                RowPainter rp(pi, *text_, pit, row, bidi, x, y);
 
                if (selection)
-                       row.setSelection(sel_beg.pos(), sel_end.pos());
+                       row.setSelectionAndMargins(sel_beg_par, sel_end_par);
                else
                        row.setSelection(-1, -1);
+               
+               // The row knows nothing about the paragraph, so we have to check
+               // whether this row is the first or last and update the margins.
+               if (row.selection()) {
+                       if (row.sel_beg == 0)
+                               row.left_margin_sel = sel_beg.pit() < pit;
+                       if (row.sel_end == sel_end_par.lastpos())
+                               row.right_margin_sel = sel_end.pit() > pit;
+               }
 
                // Row signature; has row changed since last paint?
                row.setCrc(pm.computeRowSignature(row, bparams));
@@ -2035,34 +2048,18 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
                        pi.pain.fillRectangle(x, y - row.ascent(),
                                width(), row.height(), pi.background_color);
                }
-
-               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);
-                       }
-                       drawRowSelection(pi, x, row, beg, end, beg_margin, end_margin);
-               }
+               
+               if (row.selection())
+                       drawRowSelection(pi, x, row, cur, pit);
 
                // Instrumentation for testing row cache (see also
                // 12 lines lower):
                if (lyxerr.debugging(Debug::PAINTING) && inside
-                       && (row_selection || pi.full_repaint || row_has_changed)) {
+                       && (row.selection() || pi.full_repaint || row_has_changed)) {
                                string const foreword = text_->isMainText(bv_->buffer()) ?
                                        "main text redraw " : "inset text redraw: ";
                        LYXERR(Debug::PAINTING, foreword << "pit=" << pit << " row=" << i
-                               << " row_selection="    << row_selection
+                               << " row_selection="    << row.selection()
                                << " full_repaint="     << pi.full_repaint
                                << " row_has_changed="  << row_has_changed);
                }
@@ -2091,28 +2088,39 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type pit, int x, int y) co
 
 
 void TextMetrics::drawRowSelection(PainterInfo & pi, int x, Row const & row,
-               DocIterator const & beg, DocIterator const & end,
-               bool drawOnBegMargin, bool drawOnEndMargin) const
+               Cursor const & curs, pit_type pit) 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();
 
        // draw the margins
-       if (drawOnBegMargin) {
+       if (row.left_margin_sel) {
                if (text_->isRTL(buffer, beg.paragraph())) {
-                       int lm = bv_->leftMargin();
-                       pi.pain.fillRectangle(x + x1, y1, width() - lm - x1, y2 - y1, Color_selection);
+                       int const w = width() - bv_->leftMargin() - x1;
+                       pi.pain.fillRectangle(x + x1, y1, w, y2 - y1, Color_selection);
                } else {
-                       int rm = bv_->rightMargin();
+                       int const rm = bv_->rightMargin();
                        pi.pain.fillRectangle(rm, y1, x1 - rm, y2 - y1, Color_selection);
                }
        }
 
-       if (drawOnEndMargin) {
+       if (row.right_margin_sel) {
                if (text_->isRTL(buffer, beg.paragraph())) {
                        int rm = bv_->rightMargin();
                        pi.pain.fillRectangle(x + rm, y1, x2 - rm, y2 - y1, Color_selection);
index 1a0945d4ffa57cbb4fde7d39403268dc95a89516..78825c39852b5fb7eeda060d306649fb70f86aa3 100644 (file)
@@ -160,8 +160,7 @@ private:
 
        /// 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;
+               Cursor const & cur, pit_type const pit) const;
 
 // Temporary public:
 public: