#include "Intl.h"
#include "Language.h"
#include "LayoutFile.h"
-#include "Lexer.h"
#include "LyX.h"
#include "LyXAction.h"
#include "lyxfind.h"
#include "support/gettext.h"
#include "support/lassert.h"
#include "support/Length.h"
+#include "support/Lexer.h"
#include "support/lstrings.h"
#include "support/lyxlib.h"
#include "support/types.h"
tmpcur.clearSelection();
bv->setCursor(tmpcur);
- return bv->scrollToCursor(bv->cursor(), false, true);
+ return bv->scrollToCursor(bv->cursor(), SCROLL_TOP);
}
Private(BufferView & bv) :
update_strategy_(FullScreenUpdate),
update_flags_(Update::Force),
- cursor_(bv), anchor_pit_(0), anchor_ypos_(0),
+ cursor_(bv), anchor_pit_(0), anchor_ypos_(10000),
wh_(0), inlineCompletionUniqueChars_(0),
last_inset_(nullptr), mouse_position_cache_(),
gui_(nullptr), bookmark_edit_position_(-1),
///
map<string, Inset *> edited_insets_;
- /// When the row where the cursor lies is scrolled, this
- /// contains the scroll offset
// cache for id of the paragraph which was edited the last time
int bookmark_edit_position_;
+ /// When the row where the cursor lies is scrolled, this
+ /// contains the scroll offset
int horiz_scroll_offset_;
/// a slice pointing to the start of the row where the cursor
/// is (at last draw time)
frontend::CaretGeometry caret_geometry_;
///
bool mouse_selecting_ = false;
+ /// Reference value for statistics (essentially subtract this from the actual value to see relative counts)
+ /// (words/chars/chars no blanks)
+ int stats_ref_value_w_ = 0;
+ int stats_ref_value_c_ = 0;
+ int stats_ref_value_nb_ = 0;
+ bool stats_update_trigger_ = false;
+
};
}
+void BufferView::copySettingsFrom(BufferView const & bv)
+{
+ setCursor(bv.cursor());
+ d->anchor_pit_ = bv.d->anchor_pit_;
+ d->anchor_ypos_ = bv.d->anchor_ypos_;
+}
+
+
int BufferView::defaultMargin() const
{
// The value used to be hardcoded to 10
}
+bool BufferView::hasMathRow(MathData const * cell) const
+{
+ return d->math_rows_.find(cell) != d->math_rows_.end();
+}
+
+
MathRow const & BufferView::mathRow(MathData const * cell) const
{
auto it = d->math_rows_.find(cell);
<< flagsAsString(flags) << ") buffer: " << &buffer_);
// Case when no explicit update is requested.
- if (flags == Update::None)
+ if (flags == Update::None || !ready())
return;
/* FIXME We would like to avoid doing this here, since it is very
// First check whether the metrics and inset positions should be updated
if (flags & Update::Force) {
- // This will update the CoordCache items and replace Force
- // with ForceDraw in flags.
- updateMetrics(flags);
+ // This will compute all metrics and positions.
+ updateMetrics(true);
+ // metrics is done, full drawing is necessary now
+ flags = (flags & ~Update::Force) | Update::ForceDraw;
+ }
+ /* If a single paragraph update has been requested and we are not
+ * already repainting all, check whether this update changes the
+ * paragraph metrics. If it does, then compute all metrics (in
+ * case the paragraph is in an inset)
+ *
+ * We handle this before FitCursor because the later will require
+ * correct metrics at cursor position.
+ */
+ else if ((flags & Update::SinglePar) && !(flags & Update::ForceDraw)) {
+ if (!singleParUpdate())
+ updateMetrics(true);
}
-
- // Detect whether we can only repaint a single paragraph (if we
- // are not already redrawing all).
- // We handle this before FitCursor because the later will require
- // correct metrics at cursor position.
- if (!(flags & Update::ForceDraw)
- && (flags & Update::SinglePar)
- && !singleParUpdate())
- updateMetrics(flags);
+ else if (flags & Update::ForceDraw)
+ // This will compute only the needed metrics and update positions.
+ updateMetrics(false);
// Then make sure that the screen contains the cursor if needed
if (flags & Update::FitCursor) {
if (needsFitCursor()) {
// First try to make the selection start visible
// (which is just the cursor when there is no selection)
- scrollToCursor(d->cursor_.selectionBegin(), false, false);
- // Metrics have to be recomputed (maybe again)
- updateMetrics();
+ scrollToCursor(d->cursor_.selectionBegin(), SCROLL_VISIBLE);
+ // Metrics have to be updated
+ updateMetrics(false);
// Is the cursor visible? (only useful if cursor is at end of selection)
if (needsFitCursor()) {
// then try to make cursor visible instead
- scrollToCursor(d->cursor_, false, false);
+ scrollToCursor(d->cursor_, SCROLL_VISIBLE);
// Metrics have to be recomputed (maybe again)
- updateMetrics(flags);
+ updateMetrics(false);
}
}
- flags = flags & ~Update::FitCursor;
+ flags = (flags & ~Update::FitCursor) | Update::ForceDraw;
}
+ if (lyxrc.draw_strategy == LyXRC::DS_FULL)
+ flags = flags | Update::ForceDraw;
+
// Add flags to the the update flags. These will be reset to None
// after the redraw is actually done
d->update_flags_ = d->update_flags_ | flags;
void BufferView::updateScrollbarParameters()
{
- if (height_ == 0 && width_ == 0)
+ if (!ready())
return;
// We prefer fixed size line scrolling.
Text & t = buffer_.text();
TextMetrics & tm = d->text_metrics_[&t];
- LYXERR(Debug::GUI, " Updating scrollbar: height: "
+ LYXERR(Debug::SCROLLING, " Updating scrollbar: height: "
<< t.paragraphs().size()
<< " curr par: " << d->cursor_.bottom().pit()
<< " default height " << defaultRowHeight());
<< d->par_height_[pit]);
}
- int top_pos = first.second->position() - first.second->ascent();
- int bottom_pos = last.second->position() + last.second->descent();
+ int top_pos = first.second->top();
+ int bottom_pos = last.second->bottom();
bool first_visible = first.first == 0 && top_pos >= 0;
bool last_visible = last.first + 1 == int(parsize) && bottom_pos <= height_;
if (first_visible && last_visible) {
if (pixels == 0)
return;
- // If the offset is less than 2 screen height, prefer to scroll instead.
- if (abs(pixels) <= 2 * height_) {
+ // If part of the existing paragraphs will remain visible, prefer to
+ // scroll
+ TextMetrics const & tm = textMetrics(&buffer_.text());
+ if (tm.first().second->top() - pixels <= height_
+ && tm.last().second->bottom() - pixels >= 0) {
+ LYXERR(Debug::SCROLLING, "small skip");
d->anchor_ypos_ -= pixels;
- processUpdateFlags(Update::Force);
+ processUpdateFlags(Update::ForceDraw);
return;
}
// cut off at the top
if (pixels <= d->scrollbarParameters_.min) {
DocIterator dit = doc_iterator_begin(&buffer_);
- showCursor(dit, false, false, update);
+ showCursor(dit, SCROLL_VISIBLE, update);
LYXERR(Debug::SCROLLING, "scroll to top");
return;
}
if (pixels >= d->scrollbarParameters_.max) {
DocIterator dit = doc_iterator_end(&buffer_);
dit.backwardPos();
- showCursor(dit, false, false, update);
+ showCursor(dit, SCROLL_VISIBLE, update);
LYXERR(Debug::SCROLLING, "scroll to bottom");
return;
}
+ LYXERR(Debug::SCROLLING, "search paragraph");
// find paragraph at target position
int par_pos = d->scrollbarParameters_.min;
pit_type i = 0;
DocIterator dit = doc_iterator_begin(&buffer_);
dit.pit() = i;
LYXERR(Debug::SCROLLING, "pixels = " << pixels << " -> scroll to pit " << i);
- showCursor(dit, false, false, update);
+ showCursor(dit, SCROLL_VISIBLE, update);
}
void BufferView::recenter()
{
- showCursor(d->cursor_, true, false, true);
+ showCursor(d->cursor_, SCROLL_CENTER, true);
}
void BufferView::showCursor()
{
- showCursor(d->cursor_, false, false, true);
+ showCursor(d->cursor_, SCROLL_VISIBLE, true);
}
-void BufferView::showCursor(DocIterator const & dit,
- bool recenter, bool force, bool update)
+void BufferView::showCursor(DocIterator const & dit, ScrollType how,
+ bool update)
{
- if (scrollToCursor(dit, recenter, force) && update)
- processUpdateFlags(Update::Force);
+ if (scrollToCursor(dit, how) && update)
+ processUpdateFlags(Update::ForceDraw);
}
-bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bool force)
+bool BufferView::scrollToCursor(DocIterator const & dit, ScrollType how)
{
// We are not properly started yet, delay until resizing is done.
if (height_ == 0)
return false;
- if (recenter)
+ if (how == SCROLL_CENTER)
LYXERR(Debug::SCROLLING, "Centering cursor in workarea");
- else if (force)
+ else if (how == SCROLL_TOP)
LYXERR(Debug::SCROLLING, "Setting cursor to top of workarea");
else
LYXERR(Debug::SCROLLING, "Making sure cursor is visible in workarea");
else if (bot_pit == tm.last().first + 1)
tm.newParMetricsDown();
- if (tm.contains(bot_pit) && !force && !recenter) {
+ if (tm.contains(bot_pit) && how == SCROLL_VISIBLE) {
ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
LBUFERR(!pm.rows().empty());
// FIXME: smooth scrolling doesn't work in mathed.
tm.redoParagraph(bot_pit);
int const offset = coordOffset(dit).y_;
+ pit_type const old_pit = d->anchor_pit_;
d->anchor_pit_ = bot_pit;
CursorSlice const & cs = dit.innerTextSlice();
int const old_ypos = d->anchor_ypos_;
d->anchor_ypos_ = - offset + row_dim.ascent();
- if (recenter)
+ if (how == SCROLL_CENTER)
d->anchor_ypos_ += height_/2 - row_dim.height() / 2;
- return d->anchor_ypos_ != old_ypos;
+ else if (offset > height_)
+ d->anchor_ypos_ = height_ - offset - defaultRowHeight();
+ else
+ d->anchor_ypos_ = defaultRowHeight() * 2;
+
+ return d->anchor_ypos_ != old_ypos || d->anchor_pit_ != old_pit;
}
flag.setEnabled(cur.selection());
break;
+ case LFUN_STATISTICS_REFERENCE_CLAMP: {
+ // disable optitem reset if clamp not used
+ if (cmd.argument() == "reset" && d->stats_ref_value_c_ == 0) {
+ flag.setEnabled(false);
+ break;
+ }
+ flag.setEnabled(true);
+ break;
+
+ }
+
default:
return false;
}
success = setCursorFromEntries({id, pos},
{id_end, pos_end});
}
- if (success && scrollToCursor(d->cursor_, false, true))
+ if (success && scrollToCursor(d->cursor_, SCROLL_TOP))
dr.screenUpdate(Update::Force);
} else {
// Switch to other buffer view and resend cmd
}
case LFUN_INDEX_TAG_ALL: {
+ if (cur.pos() == 0)
+ // nothing precedes
+ break;
+
Inset * ins = cur.nextInset();
if (!ins || ins->lyxCode() != INDEX_CODE)
// not at index inset
// Get word or selection
cur.text()->selectWord(cur, WHOLE_WORD);
docstring const searched_string = cur.selectionAsString(false);
+ if (searched_string.empty())
+ break;
// Start from the beginning
lyx::dispatch(FuncRequest(LFUN_BUFFER_BEGIN));
while (findOne(this, searched_string,
}
break;
+ case LFUN_STATISTICS_REFERENCE_CLAMP: {
+ d->stats_update_trigger_ = true;
+ if (cmd.argument() == "reset") {
+ d->stats_ref_value_w_ = d->stats_ref_value_c_ = d->stats_ref_value_nb_ = 0;
+ break;
+ }
+
+ DocIterator from, to;
+ from = doc_iterator_begin(&buffer_);
+ to = doc_iterator_end(&buffer_);
+ buffer_.updateStatistics(from, to);
+
+ d->stats_ref_value_w_ = buffer_.wordCount();
+ d->stats_ref_value_c_ = buffer_.charCount(true);
+ d->stats_ref_value_nb_ = buffer_.charCount(false);
+ break;
+ }
+
+
case LFUN_SCREEN_UP:
case LFUN_SCREEN_DOWN: {
Point p = getPos(cur);
void BufferView::resize(int width, int height)
{
- // Update from work area
- width_ = width;
height_ = height;
+ // Update metrics only if width has changed
+ if (width != width_) {
+ width_ = width;
- // Clear the paragraph height cache.
- d->par_height_.clear();
- // Redo the metrics.
- updateMetrics();
+ // Clear the paragraph height cache.
+ d->par_height_.clear();
+ // Redo the metrics.
+ updateMetrics(true);
+ }
+ // metrics is OK, full drawing is necessary now
+ d->update_flags_ = (d->update_flags_ & ~Update::Force) | Update::ForceDraw;
+ d->update_strategy_ = FullScreenUpdate;
}
}
+int BufferView::stats_ref_value_w() const
+{
+ return d->stats_ref_value_w_;
+}
+
+
+int BufferView::stats_ref_value_c() const
+{
+ return d->stats_ref_value_c_;
+}
+
+
+int BufferView::stats_ref_value_nb() const
+{
+ return d->stats_ref_value_nb_;
+}
+
+
void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
{
//lyxerr << "[ cmd0 " << cmd0 << "]" << endl;
+ if (!ready())
+ return;
+
// This is only called for mouse related events including
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
- Cursor old = cursor();
- Cursor cur(*this);
- cur.push(buffer_.inset());
- cur.selection(d->cursor_.selection());
-
// Either the inset under the cursor or the
// surrounding Text will handle this event.
return;
}
+ Cursor old = cursor();
+ Cursor cur(*this);
+ cur.push(buffer_.inset());
+ cur.selection(d->cursor_.selection());
+
// Build temporary cursor.
Inset * inset = d->text_metrics_[&buffer_.text()].editXY(cur, cmd.x(), cmd.y());
if (inset) {
// Put anchor at the same position.
cur.resetAnchor();
- cur.beginUndoGroup();
+ old.beginUndoGroup();
// Try to dispatch to an non-editable inset near this position
// via the temp cursor. If the inset wishes to change the real
cursor().fixIfBroken();
}
- cur.endUndoGroup();
+ old.endUndoGroup();
// Do we have a selection?
theSelection().haveSelection(cursor().selection());
int const ymax = height_ + pixels;
while (true) {
pair<pit_type, ParagraphMetrics const *> last = tm.last();
- int bottom_pos = last.second->position() + last.second->descent();
+ int bottom_pos = last.second->bottom();
if (lyxrc.scroll_below_document)
bottom_pos += height_ - minVisiblePart();
if (last.first + 1 == int(text->paragraphs().size())) {
int ymin = - pixels;
while (true) {
pair<pit_type, ParagraphMetrics const *> first = tm.first();
- int top_pos = first.second->position() - first.second->ascent();
+ int top_pos = first.second->top();
if (first.first == 0) {
if (top_pos >= 0)
return 0;
}
+void BufferView::setSelection(DocIterator const & from,
+ DocIterator const & to)
+{
+ if (from.pit() != to.pit()) {
+ // there are multiple paragraphs in selection
+ cursor().setCursor(from);
+ cursor().clearSelection();
+ cursor().selection(true);
+ cursor().setCursor(to);
+ cursor().selection(true);
+ } else {
+ // only single paragraph
+ int const size = to.pos() - from.pos();
+ putSelectionAt(from, size, false);
+ }
+ processUpdateFlags(Update::Force | Update::FitCursor);
+}
+
+
bool BufferView::selectIfEmpty(DocIterator & cur)
{
if ((cur.inTexted() && !cur.paragraph().empty())
bool BufferView::singleParUpdate()
{
- Text & buftext = buffer_.text();
- pit_type const bottom_pit = d->cursor_.bottom().pit();
- TextMetrics & tm = textMetrics(&buftext);
- Dimension const old_dim = tm.parMetrics(bottom_pit).dim();
+ CursorSlice const & its = d->cursor_.innerTextSlice();
+ pit_type const pit = its.pit();
+ TextMetrics & tm = textMetrics(its.text());
+ Dimension const old_dim = tm.parMetrics(pit).dim();
// make sure inline completion pointer is ok
if (d->inlineCompletionPos_.fixIfBroken())
d->inlineCompletionPos_ = DocIterator();
- // In Single Paragraph mode, rebreak only
- // the (main text, not inset!) paragraph containing the cursor.
- // (if this paragraph contains insets etc., rebreaking will
- // recursively descend)
- tm.redoParagraph(bottom_pit);
- ParagraphMetrics & pm = tm.parMetrics(bottom_pit);
- if (pm.height() != old_dim.height()) {
- // Paragraph height has changed so we cannot proceed to
- // the singlePar optimisation.
+ /* Try to rebreak only the paragraph containing the cursor (if
+ * this paragraph contains insets etc., rebreaking will
+ * recursively descend). We need a full redraw if either
+ * 1/ the height has changed
+ * or
+ * 2/ the width has changed and it was equal to the textmetrics
+ * width; the goal is to catch the case of a one-row inset that
+ * grows with its contents, but optimize the case of typing at
+ * the end of a mmultiple-row paragraph.
+ *
+ * NOTE: if only the height has changed, then it should be
+ * possible to update all metrics at minimal cost. However,
+ * since this is risky, we do not try that right now.
+ */
+ tm.redoParagraph(pit);
+ ParagraphMetrics & pm = tm.parMetrics(pit);
+ if (pm.height() != old_dim.height()
+ || (pm.width() != old_dim.width() && old_dim.width() == tm.width())) {
+ // Paragraph height or width has changed so we cannot proceed
+ // to the singlePar optimisation.
+ LYXERR(Debug::PAINTING, "SinglePar optimization failed.");
return false;
}
// Since position() points to the baseline of the first row, we
// the height does not change but the ascent does.
pm.setPosition(pm.position() - old_dim.ascent() + pm.ascent());
- tm.updatePosCache(bottom_pit);
+ tm.updatePosCache(pit);
- LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent()
- << " y2: " << pm.position() + pm.descent()
- << " pit: " << bottom_pit
- << " singlepar: 1");
+ LYXERR(Debug::PAINTING, "\ny1: " << pm.top() << " y2: " << pm.bottom()
+ << " pit: " << pit << " singlepar: 1");
return true;
}
void BufferView::updateMetrics()
{
- updateMetrics(d->update_flags_);
+ updateMetrics(true);
+ // metrics is done, full drawing is necessary now
+ d->update_flags_ = (d->update_flags_ & ~Update::Force) | Update::ForceDraw;
d->update_strategy_ = FullScreenUpdate;
}
-void BufferView::updateMetrics(Update::flags & update_flags)
+void BufferView::updateMetrics(bool force)
{
- if (height_ == 0 || width_ == 0)
+ if (!ready())
return;
+ //LYXERR0("updateMetrics " << _v_(force));
+
Text & buftext = buffer_.text();
- pit_type const npit = int(buftext.paragraphs().size());
+ pit_type const lastpit = int(buftext.paragraphs().size()) - 1;
- // Clear out the position cache in case of full screen redraw,
- d->coord_cache_.clear();
- d->math_rows_.clear();
+ if (force) {
+ // Clear out the position cache in case of full screen redraw,
+ d->coord_cache_.clear();
+ d->math_rows_.clear();
- // Clear out paragraph metrics to avoid having invalid metrics
- // in the cache from paragraphs not relayouted below
- // The complete text metrics will be redone.
- d->text_metrics_.clear();
+ // Clear out paragraph metrics to avoid having invalid metrics
+ // in the cache from paragraphs not relayouted below. The
+ // complete text metrics will be redone.
+ d->text_metrics_.clear();
+ }
+ // This should not be moved earlier
TextMetrics & tm = textMetrics(&buftext);
// make sure inline completion pointer is ok
if (d->inlineCompletionPos_.fixIfBroken())
d->inlineCompletionPos_ = DocIterator();
- if (d->anchor_pit_ >= npit)
+ if (d->anchor_pit_ > lastpit)
// The anchor pit must have been deleted...
- d->anchor_pit_ = npit - 1;
+ d->anchor_pit_ = lastpit;
- // Rebreak anchor paragraph.
- tm.redoParagraph(d->anchor_pit_);
- ParagraphMetrics & anchor_pm = tm.parMetrics(d->anchor_pit_);
+ // Update metrics around the anchor
+ tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
- // position anchor
- if (d->anchor_pit_ == 0) {
- int scrollRange = d->scrollbarParameters_.max - d->scrollbarParameters_.min;
+ // Check that the end of the document is not too high
+ int const min_visible = lyxrc.scroll_below_document ? minVisiblePart() : height_;
+ if (tm.last().first == lastpit && tm.last().second->hasPosition()
+ && tm.last().second->bottom() < min_visible) {
+ d->anchor_ypos_ += min_visible - tm.last().second->bottom();
+ LYXERR(Debug::SCROLLING, "Too high, adjusting anchor ypos to " << d->anchor_ypos_);
+ tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
+ }
- // Complete buffer visible? Then it's easy.
- if (scrollRange == 0)
- d->anchor_ypos_ = anchor_pm.ascent();
- else {
- // avoid empty space above the first row
- d->anchor_ypos_ = min(d->anchor_ypos_, anchor_pm.ascent());
- }
- }
- anchor_pm.setPosition(d->anchor_ypos_);
- tm.updatePosCache(d->anchor_pit_);
-
- LYXERR(Debug::PAINTING, "metrics: "
- << " anchor pit = " << d->anchor_pit_
- << " anchor ypos = " << d->anchor_ypos_);
-
- // Redo paragraphs above anchor if necessary.
- int y1 = d->anchor_ypos_ - anchor_pm.ascent();
- // We are now just above the anchor paragraph.
- pit_type pit1 = d->anchor_pit_ - 1;
- for (; pit1 >= 0 && y1 >= 0; --pit1) {
- tm.redoParagraph(pit1);
- ParagraphMetrics & pm = tm.parMetrics(pit1);
- y1 -= pm.descent();
- // Save the paragraph position in the cache.
- pm.setPosition(y1);
- tm.updatePosCache(pit1);
- y1 -= pm.ascent();
- }
-
- // Redo paragraphs below the anchor if necessary.
- int y2 = d->anchor_ypos_ + anchor_pm.descent();
- // We are now just below the anchor paragraph.
- pit_type pit2 = d->anchor_pit_ + 1;
- for (; pit2 < npit && y2 <= height_; ++pit2) {
- tm.redoParagraph(pit2);
- ParagraphMetrics & pm = tm.parMetrics(pit2);
- y2 += pm.ascent();
- // Save the paragraph position in the cache.
- pm.setPosition(y2);
- tm.updatePosCache(pit2);
- y2 += pm.descent();
- }
-
- LYXERR(Debug::PAINTING, "Metrics: "
- << " anchor pit = " << d->anchor_pit_
- << " anchor ypos = " << d->anchor_ypos_
- << " y1 = " << y1
- << " y2 = " << y2
- << " pit1 = " << pit1
- << " pit2 = " << pit2);
+ // Check that the start of the document is not too low
+ if (tm.first().first == 0 && tm.first().second->hasPosition()
+ && tm.first().second->top() > 0) {
+ d->anchor_ypos_ -= tm.first().second->top();
+ LYXERR(Debug::SCROLLING, "Too low, adjusting anchor ypos to " << d->anchor_ypos_);
+ tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
+ }
- // metrics is done, full drawing is necessary now
- update_flags = (update_flags & ~Update::Force) | Update::ForceDraw;
+ /* FIXME: do we want that? It avoids potential issues with old
+ * paragraphs that should have been recomputed but have not, at
+ * the price of potential extra metrics computation. I do not
+ * think that the performance gain is high, so that for now the
+ * extra paragraphs are removed
+ */
+ // Remove paragraphs that are outside of screen
+ while(!tm.first().second->hasPosition() || tm.first().second->bottom() <= 0) {
+ //LYXERR0("Forget pit: " << tm.first().first);
+ tm.forget(tm.first().first);
+ }
+ while(!tm.last().second->hasPosition() || tm.last().second->top() > height_) {
+ //LYXERR0("Forget pit: " << tm.first().first);
+ tm.forget(tm.last().first);
+ }
+
+ /* FIXME: if paragraphs outside of the screen are not removed
+ * above, one has to search for the first visible one here */
+ // Normalize anchor for next time
+ if (d->anchor_pit_ != tm.first().first
+ || d->anchor_ypos_ != tm.first().second->position()) {
+ LYXERR(Debug::PAINTING, __func__ << ": Found new anchor pit = " << tm.first().first
+ << " anchor ypos = " << tm.first().second->position()
+ << " (was " << d->anchor_pit_ << ", " << d->anchor_ypos_ << ")");
+ d->anchor_pit_ = tm.first().first;
+ d->anchor_ypos_ = tm.first().second->position();
+ }
// Now update the positions of insets in the cache.
updatePosCache();
// set main language of imported file to context language
buf.changeLanguage(buf.language(), d->cursor_.getFont().language());
buffer_.undo().recordUndo(d->cursor_);
+ cap::replaceSelection(d->cursor_);
cap::pasteParagraphList(d->cursor_, pars,
buf.params().documentClassPtr(),
buf.params().authors(), el);
void BufferView::caretPosAndDim(Point & p, Dimension & dim) const
{
Cursor const & cur = cursor();
- if (cur.inMathed()) {
+ if (cur.inMathed() && hasMathRow(&cur.cell())) {
MathRow const & mrow = mathRow(&cur.cell());
dim = mrow.caret_dim;
} else {
bool const slant = fm.italic() && cur.inTexted() && !cur.selection();
double const slope = slant ? fm.italicSlope() : 0;
cg.shapes.push_back(
- {{iround(p.x_ + dim.asc * slope), p.y_},
- {iround(p.x_ - dim.des * slope), p.y_ + dim.height()},
+ {{iround(p.x_ + dim.asc * slope), p.y_},
+ {iround(p.x_ - dim.des * slope), p.y_ + dim.height()},
{iround(p.x_ + dir * dim.wid - dim.des * slope), p.y_ + dim.height()},
{iround(p.x_ + dir * dim.wid + dim.asc * slope), p.y_}}
);
int const xx = iround(p.x_ - dim.des * slope);
int const yy = p.y_ + dim.height();
cg.shapes.push_back(
- {{xx, yy - dim.wid},
+ {{xx, yy - dim.wid},
{xx + dir * (dim.wid + lx - 1), yy - dim.wid},
{xx + dir * (dim.wid + lx - 1), yy},
- {xx, yy}}
+ {xx, yy}}
);
}
// starting position x
int const xx = p.x_ + dir * dim.wid + sx;
cg.shapes.push_back(
- {{xx, m - d},
- {xx + dir * d, m},
- {xx, m + d},
- {xx, m + d - dim.wid},
+ {{xx, m - d},
+ {xx + dir * d, m},
+ {xx, m + d},
+ {xx, m + d - dim.wid},
{xx + dir * d - dim.wid, m},
- {xx, m - d + dim.wid}}
+ {xx, m - d + dim.wid}}
);
}
}
+bool BufferView::busy() const
+{
+ return buffer().undo().activeUndoGroup();
+}
+
+
void BufferView::draw(frontend::Painter & pain, bool paint_caret)
{
- if (height_ == 0 || width_ == 0)
+ if (!ready())
return;
LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t--- START NODRAW ---"
: "\t\t*** START DRAWING ***"));
// Draw everything.
tm.draw(pi, 0, y);
- // and possibly grey out below
+ break;
+ }
+
+ // Possibly grey out below
+ if (d->update_strategy_ != NoScreenUpdate) {
pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
- int const y2 = lastpm.second->position() + lastpm.second->descent();
+ int const y2 = lastpm.second->bottom();
if (y2 < height_) {
Color color = buffer().isInternal()
? Color_background : Color_bottomarea;
pain.fillRectangle(0, y2, width_, height_ - y2, color);
}
- break;
}
+
LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t --- END NODRAW ---"
: "\t\t *** END DRAWING ***"));
// FIXME: does it always? see ticket #11947.
updateScrollbarParameters();
- // Normalize anchor for next time
+ // Normalize anchor for next time (in case updateMetrics did not do it yet)
+ // FIXME: is this useful?
pair<pit_type, ParagraphMetrics const *> firstpm = tm.first();
pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
ParagraphMetrics const & pm = tm.parMetrics(pit);
- if (pm.position() + pm.descent() > 0) {
+ if (pm.bottom() > 0) {
if (d->anchor_pit_ != pit
|| d->anchor_ypos_ != pm.position())
- LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_
- << " anchor ypos = " << d->anchor_ypos_);
+ LYXERR0(__func__ << ": Found new anchor pit = " << pit
+ << " anchor ypos = " << pm.position()
+ << " (was " << d->anchor_pit_ << ", " << d->anchor_ypos_ << ")"
+ "\nIf you see this message, please report.");
d->anchor_pit_ = pit;
d->anchor_ypos_ = pm.position();
break;
}
}
+
if (!pain.isNull()) {
// reset the update flags, everything has been done
d->update_flags_ = Update::None;
return d->clickable_inset_;
}
+
+bool BufferView::stats_update_trigger()
+{
+ if (d->stats_update_trigger_) {
+ d->stats_update_trigger_ = false;
+ return true;
+ }
+ return false;
+}
+
} // namespace lyx