]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Fulfill promise to Andre: TextClass_ptr --> TextClassPtr.
[lyx.git] / src / BufferView.cpp
index b7776050cd95b041b250c6ba6e1b036a5001d702..f1cf7c1f817537b7ec37bd203b6ad709db3d4f5f 100644 (file)
@@ -21,6 +21,7 @@
 #include "BufferList.h"
 #include "BufferParams.h"
 #include "bufferview_funcs.h"
+#include "callback.h" // added for Dispatch functions
 #include "CoordCache.h"
 #include "CutAndPaste.h"
 #include "debug.h"
 #include "InsetIterator.h"
 #include "Language.h"
 #include "LaTeXFeatures.h"
-#include "callback.h" // added for Dispatch functions
 #include "LyX.h"
 #include "lyxfind.h"
 #include "LyXFunc.h"
 #include "Layout.h"
-#include "Text.h"
-#include "TextClass.h"
 #include "LyXRC.h"
-#include "Session.h"
+#include "MetricsInfo.h"
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
 #include "ParIterator.h"
+#include "Session.h"
 #include "TexRow.h"
+#include "Text.h"
+#include "TextClass.h"
 #include "toc.h"
 #include "Undo.h"
 #include "VSpace.h"
 #include "WordLangTuple.h"
-#include "MetricsInfo.h"
 
 #include "insets/InsetBibtex.h"
 #include "insets/InsetCommand.h" // ChangeRefs
@@ -63,6 +63,7 @@
 #include "frontends/alert.h"
 #include "frontends/FileDialog.h"
 #include "frontends/FontMetrics.h"
+#include "frontends/Painter.h"
 #include "frontends/Selection.h"
 
 #include "graphics/Previews.h"
@@ -126,14 +127,14 @@ BufferView::BufferView(Buffer & buf)
        : width_(0), height_(0), buffer_(buf), wh_(0),
          cursor_(*this),
          multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0),
-         intl_(new Intl), last_inset_(0)
+         need_centering_(false), intl_(new Intl), last_inset_(0)
 {
        xsel_cache_.set = false;
        intl_->initKeyMapper(lyxrc.use_kbmap);
 
        cursor_.push(buffer_.inset());
        cursor_.resetAnchor();
-       buffer_.text().setCurrentFont(cursor_);
+       cursor_.setCurrentFont();
 
        if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
                graphics::Previews::get().generateBufferPreviews(buffer_);
@@ -142,6 +143,14 @@ BufferView::BufferView(Buffer & buf)
 
 BufferView::~BufferView()
 {
+       // current buffer is going to be switched-off, save cursor pos
+       // Ideally, the whole cursor stack should be saved, but session
+       // currently can only handle bottom (whole document) level pit and pos.
+       // That is to say, if a cursor is in a nested inset, it will be
+       // restore to the left of the top level inset.
+       LyX::ref().session().lastFilePos().save(
+               support::FileName(buffer_.fileName()),
+               boost::tie(cursor_.bottom().pit(), cursor_.bottom().pos()) );
 }
 
 
@@ -330,12 +339,13 @@ void BufferView::scrollDocView(int value)
        int const h = tm.parMetrics(anchor_ref_).height();
        offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h);
        updateMetrics(false);
+       buffer_.changed();
 }
 
 
 void BufferView::setCursorFromScrollbar()
 {
-       Text & t = buffer_.text();
+       TextMetrics & tm = text_metrics_[&buffer_.text()];
 
        int const height = 2 * defaultRowHeight();
        int const first = height;
@@ -349,14 +359,14 @@ void BufferView::setCursorFromScrollbar()
                // We reset the cursor because bv_funcs::status() does not
                // work when the cursor is within mathed.
                cur.reset(buffer_.inset());
-               t.setCursorFromCoordinates(cur, 0, first);
+               tm.setCursorFromCoordinates(cur, 0, first);
                cur.clearSelection();
                break;
        case bv_funcs::CUR_BELOW:
                // We reset the cursor because bv_funcs::status() does not
                // work when the cursor is within mathed.
                cur.reset(buffer_.inset());
-               t.setCursorFromCoordinates(cur, 0, last);
+               tm.setCursorFromCoordinates(cur, 0, last);
                cur.clearSelection();
                break;
        case bv_funcs::CUR_INSIDE:
@@ -364,7 +374,7 @@ void BufferView::setCursorFromScrollbar()
                int const newy = min(last, max(y, first));
                if (y != newy) {
                        cur.reset(buffer_.inset());
-                       t.setCursorFromCoordinates(cur, 0, newy);
+                       tm.setCursorFromCoordinates(cur, 0, newy);
                }
        }
 }
@@ -400,9 +410,12 @@ void BufferView::saveBookmark(unsigned int idx)
 }
 
 
-boost::tuple<pit_type, pos_type, int> BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
+bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
        int top_id, pos_type top_pos)
 {
+       bool success = false;
+       DocIterator doc_it;
+
        cursor_.clearSelection();
 
        // if a valid par_id is given, try it first
@@ -411,24 +424,23 @@ boost::tuple<pit_type, pos_type, int> BufferView::moveToPosition(pit_type bottom
        if (top_id > 0) {
                ParIterator par = buffer_.getParFromID(top_id);
                if (par != buffer_.par_iterator_end()) {
-                       DocIterator dit = makeDocIterator(par, min(par->size(), top_pos));
+                       doc_it = makeDocIterator(par, min(par->size(), top_pos));
                        // Some slices of the iterator may not be
                        // reachable (e.g. closed collapsable inset)
                        // so the dociterator may need to be
                        // shortened. Otherwise, setCursor may crash
                        // lyx when the cursor can not be set to these
                        // insets.
-                       size_t const n = dit.depth();
+                       size_t const n = doc_it.depth();
                        for (size_t i = 0; i < n; ++i)
-                               if (dit[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
-                                       dit.resize(i);
+                               if (doc_it[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
+                                       doc_it.resize(i);
                                        break;
                                }
-                       setCursor(dit);
-                       // Note: return bottom (document) level pit.
-                       return boost::make_tuple(cursor_.bottom().pit(), cursor_.bottom().pos(), top_id);
+                       success = true;
                }
        }
+
        // if top_id == 0, or searching through top_id failed
        // This is the case for a 'restored' bookmark when only bottom
        // (document level) pit was saved. Because of this, bookmark
@@ -436,22 +448,29 @@ boost::tuple<pit_type, pos_type, int> BufferView::moveToPosition(pit_type bottom
        // it will be restored to the left of the outmost inset that contains
        // the bookmark.
        if (static_cast<size_t>(bottom_pit) < buffer_.paragraphs().size()) {
-               DocIterator it = doc_iterator_begin(buffer_.inset());
-               it.pit() = bottom_pit;
-               it.pos() = min(bottom_pos, it.paragraph().size());
-               setCursor(it);
-               return boost::make_tuple(it.pit(), it.pos(),
-                                        it.paragraph().id());
+               doc_it = doc_iterator_begin(buffer_.inset());
+               doc_it.pit() = bottom_pit;
+               doc_it.pos() = min(bottom_pos, doc_it.paragraph().size());
+               success = true;
+       }
+
+       if (success) {
+               // Note: only bottom (document) level pit is set.
+               setCursor(doc_it);
+               // set the current font.
+               cursor_.setCurrentFont();
+               // center the screen on this new position.
+               center();
        }
-       // both methods fail
-       return boost::make_tuple(pit_type(0), pos_type(0), 0);
+
+       return success;
 }
 
 
 void BufferView::translateAndInsert(char_type c, Text * t, Cursor & cur)
 {
        if (lyxrc.rtl_support) {
-               if (cursor_.innerText()->real_current_font.isRightToLeft()) {
+               if (cursor_.real_current_font.isRightToLeft()) {
                        if (intl_->keymap == Intl::PRIMARY)
                                intl_->keyMapSec();
                } else {
@@ -459,7 +478,7 @@ void BufferView::translateAndInsert(char_type c, Text * t, Cursor & cur)
                                intl_->keyMapPrim();
                }
        }
-       
+
        intl_->getTransManager().translateAndInsert(c, t, cur);
 }
 
@@ -470,16 +489,31 @@ int BufferView::workWidth() const
 }
 
 
-void BufferView::center()
+void BufferView::updateOffsetRef()
 {
+       // No need to update offset_ref_ in this case.
+       if (!need_centering_)
+               return;
+
+       // We are not properly started yet, delay until resizing is
+       // done.
+       if (height_ == 0)
+               return;
+
        CursorSlice & bot = cursor_.bottom();
        TextMetrics & tm = text_metrics_[bot.text()];
-       pit_type const pit = bot.pit();
-       tm.redoParagraph(pit);
-       ParagraphMetrics const & pm = tm.parMetrics(pit);
-       anchor_ref_ = pit;
-       offset_ref_ = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary()).y_
-               + pm.ascent() - height_ / 2;
+       ParagraphMetrics const & pm = tm.parMetrics(bot.pit());
+       Point p = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary());
+       offset_ref_ = p.y_ + pm.ascent() - height_ / 2;
+
+       need_centering_ = false;
+}
+
+
+void BufferView::center()
+{
+       anchor_ref_ = cursor_.bottom().pit();
+       need_centering_ = true;
 }
 
 
@@ -559,6 +593,18 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd)
                break;
        }
 
+       case LFUN_SCREEN_UP:
+       case LFUN_SCREEN_DOWN:
+               flag.enabled(true);
+               break;
+
+       // FIXME: LFUN_SCREEN_DOWN_SELECT should be removed from
+       // everywhere else before this can enabled:
+       case LFUN_SCREEN_UP_SELECT:
+       case LFUN_SCREEN_DOWN_SELECT:
+               flag.enabled(false);
+               break;
+
        default:
                flag.enabled(false);
        }
@@ -880,12 +926,16 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
                // if there is an inset at cursor, see whether it
                // wants to toggle.
                Inset * inset = cur.nextInset();
-               if (inset && inset->isActive()) {
-                       Cursor tmpcur = cur;
-                       tmpcur.pushLeft(*inset);
-                       inset->dispatch(tmpcur, tmpcmd);
-                       if (tmpcur.result().dispatched()) {
-                               cur.dispatched();
+               if (inset) {
+                       if (inset->isActive()) {
+                               Cursor tmpcur = cur;
+                               tmpcur.pushLeft(*inset);
+                               inset->dispatch(tmpcur, tmpcmd);
+                               if (tmpcur.result().dispatched()) {
+                                       cur.dispatched();
+                               }
+                       } else if (inset->editable() == Inset::IS_EDITABLE) {
+                               inset->edit(cur, true);
                        }
                }
                // if it did not work, try the underlying inset.
@@ -898,6 +948,47 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd)
                break;
        }
 
+       case LFUN_SCREEN_UP:
+       case LFUN_SCREEN_DOWN: {
+               Point p = bv_funcs::getPos(*this, cur, cur.boundary());
+               if (p.y_ < 0 || p.y_ > height_) {
+                       // The cursor is off-screen so recenter before proceeding.
+                       center();
+                       updateMetrics(false);
+                       //FIXME: updateMetrics() does not update paragraph position
+                       // This is done at draw() time. So we need a redraw!
+                       buffer_.changed();
+                       p = bv_funcs::getPos(*this, cur, cur.boundary());
+               }
+               scroll(cmd.action == LFUN_SCREEN_UP? - height_ : height_);
+               cur.reset(buffer_.inset());
+               text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_);
+               //FIXME: what to do with cur.x_target()?
+               finishUndo();
+               // The metrics are already up to date. see scroll()
+               updateFlags = Update::None;
+               break;
+       }
+
+       case LFUN_SCREEN_UP_SELECT:
+       case LFUN_SCREEN_DOWN_SELECT: {
+               cur.selHandle(true);
+               size_t initial_depth = cur.depth();
+               Point const p = bv_funcs::getPos(*this, cur, cur.boundary());
+               scroll(cmd.action == LFUN_SCREEN_UP_SELECT? - height_ : height_);
+               // FIXME: We need to verify if the cursor stayed within an inset...
+               //cur.reset(buffer_.inset());
+               text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_);
+               finishUndo();
+               while (cur.depth() > initial_depth) {
+                       cur.forwardInset();
+               }
+               // FIXME: we need to do a redraw again because of the selection
+               buffer_.changed();
+               updateFlags = Update::Force | Update::FitCursor;
+               break;
+       }
+
        default:
                updateFlags = Update::None;
        }
@@ -942,21 +1033,19 @@ void BufferView::clearSelection()
 }
 
 
-void BufferView::workAreaResize(int width, int height)
+void BufferView::resize(int width, int height)
 {
        // Update from work area
        width_ = width;
        height_ = height;
 
-       // The complete text metrics will be redone.
-       text_metrics_.clear();
        updateMetrics(false);
 }
 
 
 Inset const * BufferView::getCoveringInset(Text const & text, int x, int y)
 {
-       pit_type pit = text.getPitNearY(*this, y);
+       pit_type pit = text_metrics_[&text].getPitNearY(y);
        BOOST_ASSERT(pit != -1);
        Paragraph const & par = text.getPar(pit);
 
@@ -1021,6 +1110,9 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
        cmd.y = min(max(cmd.y, -1), height_);
 
        if (cmd.action == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) {
+               //FIXME: disabling mouse hover for now as it is causing funny things
+               // on screen.
+               return false;
 
                // Get inset under mouse, if there is one.
                Inset const * covering_inset =
@@ -1053,7 +1145,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
                        //metrics_info_.y1 = ymin of button;
                        //metrics_info_.y2 = ymax of button;
                        //
-                       // Unfortunately, rowpainter.cpp:paintText() does not distinguish
+                       // Unfortunately, BufferView::draw() does not distinguish
                        // between background updates and text updates. So we use the hammer
                        // solution for now. We could also avoid the updateMetrics() below
                        // by using the first and last pit of the CoordCache. Have a look
@@ -1074,7 +1166,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
        }
 
        // Build temporary cursor.
-       Inset * inset = buffer_.text().editXY(cur, cmd.x, cmd.y);
+       Inset * inset = text_metrics_[&buffer_.text()].editXY(cur, cmd.x, cmd.y);
 
        // Put anchor at the same position.
        cur.resetAnchor();
@@ -1103,20 +1195,60 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
 }
 
 
-void BufferView::scroll(int /*lines*/)
+void BufferView::scroll(int y)
+{
+       if (y > 0)
+               scrollDown(y);
+       else if (y < 0)
+               scrollUp(-y);
+}
+
+
+void BufferView::scrollDown(int offset)
 {
-//     Text const * t = buffer_.text();
-//     int const line_height = defaultRowHeight();
-//
-//     // The new absolute coordinate
-//     int new_top_y = top_y() + lines * line_height;
-//
-//     // Restrict to a valid value
-//     new_top_y = std::min(t->height() - 4 * line_height, new_top_y);
-//     new_top_y = std::max(0, new_top_y);
-//
-//     scrollDocView(new_top_y);
-//
+       Text * text = &buffer_.text();
+       TextMetrics & tm = text_metrics_[text];
+       int ymax = height_ + offset;
+       while (true) {
+               std::pair<pit_type, ParagraphMetrics> const & last = tm.last();
+               int bottom_pos = last.second.position() + last.second.descent();
+               if (last.first == text->paragraphs().size() - 1) {
+                       if (bottom_pos <= height_)
+                               return;
+                       offset = min(offset, bottom_pos - height_);
+                       break;
+               }
+               if (bottom_pos > ymax)
+                       break;
+               tm.newParMetricsDown();
+       }
+       offset_ref_ += offset;
+       updateMetrics(false);
+       buffer_.changed();
+}
+
+
+void BufferView::scrollUp(int offset)
+{
+       Text * text = &buffer_.text();
+       TextMetrics & tm = text_metrics_[text];
+       int ymin = - offset;
+       while (true) {
+               std::pair<pit_type, ParagraphMetrics> const & first = tm.first();
+               int top_pos = first.second.position() - first.second.ascent();
+               if (first.first == 0) {
+                       if (top_pos >= 0)
+                               return;
+                       offset = min(offset, - top_pos);
+                       break;
+               }
+               if (top_pos < ymin)
+                       break;
+               tm.newParMetricsUp();
+       }
+       offset_ref_ -= offset;
+       updateMetrics(false);
+       buffer_.changed();
 }
 
 
@@ -1218,7 +1350,7 @@ bool BufferView::mouseSetCursor(Cursor & cur)
 {
        BOOST_ASSERT(&cur.bv() == this);
 
-        // this event will clear selection so we save selection for
+       // this event will clear selection so we save selection for
        // persistent selection
        cap::saveSelection(cursor());
 
@@ -1306,23 +1438,26 @@ ViewMetricsInfo const & BufferView::viewMetricsInfo()
 void BufferView::updateMetrics(bool singlepar)
 {
        Text & buftext = buffer_.text();
-       TextMetrics & tm = textMetrics(&buftext);
-       pit_type size = int(buftext.paragraphs().size());
+       pit_type const npit = int(buftext.paragraphs().size());
 
-       if (anchor_ref_ > int(buftext.paragraphs().size() - 1)) {
-               anchor_ref_ = int(buftext.paragraphs().size() - 1);
+       if (anchor_ref_ > int(npit - 1)) {
+               anchor_ref_ = int(npit - 1);
                offset_ref_ = 0;
        }
 
        if (!singlepar) {
                // Clear out the position cache in case of full screen redraw,
                coord_cache_.clear();
-       
+
                // Clear out paragraph metrics to avoid having invalid metrics
                // in the cache from paragraphs not relayouted below
-               tm.clear();
+               // The complete text metrics will be redone.
+               text_metrics_.clear();
        }
 
+       TextMetrics & tm = textMetrics(&buftext);
+
+       pit_type const bottom_pit = cursor_.bottom().pit();
        // If the paragraph metrics has changed, we can not
        // use the singlepar optimisation.
        if (singlepar
@@ -1330,17 +1465,33 @@ void BufferView::updateMetrics(bool singlepar)
                // the (main text, not inset!) paragraph containing the cursor.
                // (if this paragraph contains insets etc., rebreaking will
                // recursively descend)
-               && tm.redoParagraph(cursor_.bottom().pit()))
-               singlepar = false;
+               && !tm.redoParagraph(bottom_pit)) {
+
+               updateOffsetRef();
+               // collect cursor paragraph iter bounds
+               ParagraphMetrics const & pm = tm.parMetrics(bottom_pit);
+               int y1 = pm.position() - pm.ascent();
+               int y2 = pm.position() + pm.descent();
+               metrics_info_ = ViewMetricsInfo(bottom_pit, bottom_pit, y1, y2,
+                       SingleParUpdate, npit);
+               LYXERR(Debug::PAINTING)
+                       << BOOST_CURRENT_FUNCTION
+                       << "\ny1: " << y1
+                       << " y2: " << y2
+                       << " pit: " << bottom_pit
+                       << " singlepar: " << singlepar
+                       << endl;
+               return;
+       }
 
        pit_type const pit = anchor_ref_;
        int pit1 = pit;
        int pit2 = pit;
-       size_t const npit = buftext.paragraphs().size();
 
        // Rebreak anchor paragraph.
-       if (!singlepar)
-               tm.redoParagraph(pit);
+       tm.redoParagraph(pit);
+
+       updateOffsetRef();
 
        int y0 = tm.parMetrics(pit).ascent() - offset_ref_;
 
@@ -1349,12 +1500,10 @@ void BufferView::updateMetrics(bool singlepar)
        while (y1 > 0 && pit1 > 0) {
                y1 -= tm.parMetrics(pit1).ascent();
                --pit1;
-               if (!singlepar)
-                       tm.redoParagraph(pit1);
+               tm.redoParagraph(pit1);
                y1 -= tm.parMetrics(pit1).descent();
        }
 
-
        // Take care of ascent of first line
        y1 -= tm.parMetrics(pit1).ascent();
 
@@ -1374,49 +1523,25 @@ void BufferView::updateMetrics(bool singlepar)
        while (y2 < height_ && pit2 < int(npit) - 1) {
                y2 += tm.parMetrics(pit2).descent();
                ++pit2;
-               if (!singlepar)
-                       tm.redoParagraph(pit2);
+               tm.redoParagraph(pit2);
                y2 += tm.parMetrics(pit2).ascent();
        }
 
        // Take care of descent of last line
        y2 += tm.parMetrics(pit2).descent();
 
-       // The coordinates of all these paragraphs are correct, cache them
-       int y = y1;
-       CoordCache::InnerParPosCache & parPos = coord_cache_.parPos()[&buftext];
-       for (pit_type pit = pit1; pit <= pit2; ++pit) {
-               ParagraphMetrics const & pm = tm.parMetrics(pit);
-               y += pm.ascent();
-               parPos[pit] = Point(0, y);
-               if (singlepar && pit == cursor_.bottom().pit()) {
-                       // In Single Paragraph mode, collect here the
-                       // y1 and y2 of the (one) paragraph the cursor is in
-                       y1 = y - pm.ascent();
-                       y2 = y + pm.descent();
-               }
-               y += pm.descent();
-       }
-
-       if (singlepar) {
-               // collect cursor paragraph iter bounds
-               pit1 = cursor_.bottom().pit();
-               pit2 = cursor_.bottom().pit();
-       }
-
-       LYXERR(Debug::DEBUG)
+       LYXERR(Debug::PAINTING)
                << BOOST_CURRENT_FUNCTION
-               << " y1: " << y1
+               << "\n y1: " << y1
                << " y2: " << y2
                << " pit1: " << pit1
                << " pit2: " << pit2
                << " npit: " << npit
                << " singlepar: " << singlepar
-               << "size: " << size
                << endl;
 
        metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2,
-               singlepar? SingleParUpdate: FullScreenUpdate, size);
+               FullScreenUpdate, npit);
 
        if (lyxerr.debugging(Debug::WORKAREA)) {
                LYXERR(Debug::WORKAREA) << "BufferView::updateMetrics" << endl;
@@ -1482,7 +1607,7 @@ void BufferView::menuInsertLyXFile(string const & filenm)
                el = buf.errorList("Parse");
                recordUndo(cursor_);
                cap::pasteParagraphList(cursor_, buf.paragraphs(),
-                                            buf.params().textclass, el);
+                                            buf.params().getTextClassPtr(), el);
                res = _("Document %1$s inserted.");
        } else
                res = _("Could not insert document %1$s");
@@ -1493,4 +1618,44 @@ void BufferView::menuInsertLyXFile(string const & filenm)
        updateMetrics(false);
 }
 
+
+void BufferView::draw(frontend::Painter & pain)
+{
+       PainterInfo pi(this, pain);
+       // Should the whole screen, including insets, be refreshed?
+       // FIXME: We should also distinguish DecorationUpdate to avoid text
+       // drawing if possible. This is not possible to do easily right now
+       // because of the single backing pixmap.
+       pi.full_repaint = metrics_info_.update_strategy != SingleParUpdate;
+
+       if (pi.full_repaint)
+               // Clear background (if not delegated to rows)
+               pain.fillRectangle(0, metrics_info_.y1, width_,
+                       metrics_info_.y2 - metrics_info_.y1,
+                       buffer_.inset().backgroundColor());
+
+       LYXERR(Debug::PAINTING) << "\t\t*** START DRAWING ***" << endl;
+       Text & text = buffer_.text();
+       TextMetrics const & tm = text_metrics_[&text];
+       int y = metrics_info_.y1 + tm.parMetrics(metrics_info_.p1).ascent();
+       if (!pi.full_repaint)
+               tm.drawParagraph(pi, metrics_info_.p1, 0, y);
+       else
+               tm.draw(pi, 0, y);
+       LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING  ***" << endl;
+
+       // and grey out above (should not happen later)
+//     lyxerr << "par ascent: " << text.getPar(metrics_info_.p1).ascent() << endl;
+       if (metrics_info_.y1 > 0
+               && metrics_info_.update_strategy == FullScreenUpdate)
+               pain.fillRectangle(0, 0, width_, metrics_info_.y1, Color::bottomarea);
+
+       // and possibly grey out below
+//     lyxerr << "par descent: " << text.getPar(metrics_info_.p1).ascent() << endl;
+       if (metrics_info_.y2 < height_
+               && metrics_info_.update_strategy == FullScreenUpdate)
+               pain.fillRectangle(0, metrics_info_.y2, width_,
+                       height_ - metrics_info_.y2, Color::bottomarea);
+}
+
 } // namespace lyx