mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 01:59:02 +00:00
Improve the code that limits scrolling at top/bottom
The most visible part of this commit is the move of part of
BufferView::updateMetrics to a new TextMetrics::updateMetrics. This
new method makes sure that metrics are known for all visible paragraphs
(starting from anchor), and that the positions of the paragraphs have
been recorded.
This method is called up to 3 times in BufferView::updateMetrics:
* unconditionally, to update all visible metrics,
* then, if the bottom of the document is visible and too high, after
updating the anchor ypos,
* and similarly if the top of the document is visible and too low.
This fixes for example the case where one jumps to Section 5.3 at the
end of Tutorial and 'scroll_below_document' is false.
Some now redundant code is removed from BufferView::scrollToCursor.
The anchor-setting code in BufferView::draw is not clearly useful, but
left here just in case. It generates a debug warning, though.
Part of bug #12297.
(cherry picked from commit f15d2ebf38
)
This commit is contained in:
parent
2434a3a288
commit
e5aaa64b63
@ -769,6 +769,7 @@ void BufferView::scrollDocView(int const pixels, bool update)
|
|||||||
TextMetrics const & tm = textMetrics(&buffer_.text());
|
TextMetrics const & tm = textMetrics(&buffer_.text());
|
||||||
if (tm.first().second->top() - pixels <= height_
|
if (tm.first().second->top() - pixels <= height_
|
||||||
&& tm.last().second->bottom() - pixels >= 0) {
|
&& tm.last().second->bottom() - pixels >= 0) {
|
||||||
|
LYXERR(Debug::SCROLLING, "small skip");
|
||||||
d->anchor_ypos_ -= pixels;
|
d->anchor_ypos_ -= pixels;
|
||||||
processUpdateFlags(Update::ForceDraw);
|
processUpdateFlags(Update::ForceDraw);
|
||||||
return;
|
return;
|
||||||
@ -791,6 +792,7 @@ void BufferView::scrollDocView(int const pixels, bool update)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LYXERR(Debug::SCROLLING, "search paragraph");
|
||||||
// find paragraph at target position
|
// find paragraph at target position
|
||||||
int par_pos = d->scrollbarParameters_.min;
|
int par_pos = d->scrollbarParameters_.min;
|
||||||
pit_type i = 0;
|
pit_type i = 0;
|
||||||
@ -1104,8 +1106,6 @@ bool BufferView::scrollToCursor(DocIterator const & dit, ScrollType how)
|
|||||||
d->anchor_ypos_ = - offset + row_dim.ascent();
|
d->anchor_ypos_ = - offset + row_dim.ascent();
|
||||||
if (how == SCROLL_CENTER)
|
if (how == SCROLL_CENTER)
|
||||||
d->anchor_ypos_ += height_/2 - row_dim.height() / 2;
|
d->anchor_ypos_ += height_/2 - row_dim.height() / 2;
|
||||||
else if (!lyxrc.scroll_below_document && d->anchor_pit_ == max_pit)
|
|
||||||
d->anchor_ypos_ = height_ - offset - row_dim.descent();
|
|
||||||
else if (offset > height_)
|
else if (offset > height_)
|
||||||
d->anchor_ypos_ = height_ - offset - defaultRowHeight();
|
d->anchor_ypos_ = height_ - offset - defaultRowHeight();
|
||||||
else
|
else
|
||||||
@ -3184,7 +3184,7 @@ void BufferView::updateMetrics(bool force)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Text & buftext = buffer_.text();
|
Text & buftext = buffer_.text();
|
||||||
pit_type const npit = int(buftext.paragraphs().size());
|
pit_type const lastpit = int(buftext.paragraphs().size()) - 1;
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
// Clear out the position cache in case of full screen redraw,
|
// Clear out the position cache in case of full screen redraw,
|
||||||
@ -3203,62 +3203,35 @@ void BufferView::updateMetrics(bool force)
|
|||||||
if (d->inlineCompletionPos_.fixIfBroken())
|
if (d->inlineCompletionPos_.fixIfBroken())
|
||||||
d->inlineCompletionPos_ = DocIterator();
|
d->inlineCompletionPos_ = DocIterator();
|
||||||
|
|
||||||
if (d->anchor_pit_ >= npit)
|
if (d->anchor_pit_ > lastpit)
|
||||||
// The anchor pit must have been deleted...
|
// The anchor pit must have been deleted...
|
||||||
d->anchor_pit_ = npit - 1;
|
d->anchor_pit_ = lastpit;
|
||||||
|
|
||||||
if (!tm.contains(d->anchor_pit_))
|
// Update metrics around the anchor
|
||||||
// Rebreak anchor paragraph.
|
tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
|
||||||
tm.redoParagraph(d->anchor_pit_);
|
|
||||||
ParagraphMetrics & anchor_pm = tm.parMetrics(d->anchor_pit_);
|
|
||||||
|
|
||||||
// make sure than first paragraph of document is not too low
|
// Check that the end of the document is not too high
|
||||||
if (d->anchor_pit_ == 0) {
|
int const min_visible = lyxrc.scroll_below_document ? minVisiblePart() : height_;
|
||||||
int scrollRange = d->scrollbarParameters_.max - d->scrollbarParameters_.min;
|
if (tm.last().first == lastpit && tm.last().second->bottom() < min_visible) {
|
||||||
|
d->anchor_ypos_ += min_visible - tm.last().second->bottom();
|
||||||
// Complete buffer visible? Then it's easy.
|
LYXERR(Debug::SCROLLING, "Too high, adjusting anchor ypos to " << d->anchor_ypos_);
|
||||||
if (scrollRange == 0)
|
tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
|
||||||
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_);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if (!tm.contains(pit1))
|
|
||||||
tm.redoParagraph(pit1);
|
|
||||||
ParagraphMetrics & pm = tm.parMetrics(pit1);
|
|
||||||
y1 -= pm.descent();
|
|
||||||
// Save the paragraph position in the cache.
|
|
||||||
pm.setPosition(y1);
|
|
||||||
y1 -= pm.ascent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redo paragraphs below the anchor if necessary.
|
// Check that the start of the document is not too low
|
||||||
int y2 = d->anchor_ypos_ + anchor_pm.descent();
|
if (tm.first().first == 0 && tm.first().second->top() > 0) {
|
||||||
// We are now just below the anchor paragraph.
|
d->anchor_ypos_ -= tm.first().second->top();
|
||||||
pit_type pit2 = d->anchor_pit_ + 1;
|
LYXERR(Debug::SCROLLING, "Too low, adjusting anchor ypos to " << d->anchor_ypos_);
|
||||||
for (; pit2 < npit && y2 < height_; ++pit2) {
|
tm.updateMetrics(d->anchor_pit_, d->anchor_ypos_, height_);
|
||||||
if (!tm.contains(pit2))
|
|
||||||
tm.redoParagraph(pit2);
|
|
||||||
ParagraphMetrics & pm = tm.parMetrics(pit2);
|
|
||||||
y2 += pm.ascent();
|
|
||||||
// Save the paragraph position in the cache.
|
|
||||||
pm.setPosition(y2);
|
|
||||||
y2 += pm.descent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: do we want that?
|
/* FIXME: do we want that? It avoids potential issues with old
|
||||||
// if updating, remove paragraphs that are outside of screen
|
* paragraphs that should have been recomputed but have not, at
|
||||||
|
* the price of potential extra metrics computaiton. 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->bottom() <= 0) {
|
while(tm.first().second->bottom() <= 0) {
|
||||||
//LYXERR0("Forget pit: " << tm.first().first);
|
//LYXERR0("Forget pit: " << tm.first().first);
|
||||||
tm.forget(tm.first().first);
|
tm.forget(tm.first().first);
|
||||||
@ -3268,6 +3241,8 @@ void BufferView::updateMetrics(bool force)
|
|||||||
tm.forget(tm.last().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
|
// Normalize anchor for next time
|
||||||
if (d->anchor_pit_ != tm.first().first
|
if (d->anchor_pit_ != tm.first().first
|
||||||
|| d->anchor_ypos_ != tm.first().second->position()) {
|
|| d->anchor_ypos_ != tm.first().second->position()) {
|
||||||
@ -3278,14 +3253,6 @@ void BufferView::updateMetrics(bool force)
|
|||||||
d->anchor_ypos_ = tm.first().second->position();
|
d->anchor_ypos_ = tm.first().second->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
LYXERR(Debug::PAINTING, "Metrics: "
|
|
||||||
<< " anchor pit = " << d->anchor_pit_
|
|
||||||
<< " anchor ypos = " << d->anchor_ypos_
|
|
||||||
<< " y1 = " << y1
|
|
||||||
<< " y2 = " << y2
|
|
||||||
<< " pit1 = " << pit1
|
|
||||||
<< " pit2 = " << pit2);
|
|
||||||
|
|
||||||
// Now update the positions of insets in the cache.
|
// Now update the positions of insets in the cache.
|
||||||
updatePosCache();
|
updatePosCache();
|
||||||
|
|
||||||
@ -3753,6 +3720,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
|
|||||||
updateScrollbarParameters();
|
updateScrollbarParameters();
|
||||||
|
|
||||||
// Normalize anchor for next time (in case updateMetrics did not do it yet)
|
// 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 *> firstpm = tm.first();
|
||||||
pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
|
pair<pit_type, ParagraphMetrics const *> lastpm = tm.last();
|
||||||
for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
|
for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) {
|
||||||
@ -3760,9 +3728,10 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret)
|
|||||||
if (pm.bottom() > 0) {
|
if (pm.bottom() > 0) {
|
||||||
if (d->anchor_pit_ != pit
|
if (d->anchor_pit_ != pit
|
||||||
|| d->anchor_ypos_ != pm.position())
|
|| d->anchor_ypos_ != pm.position())
|
||||||
LYXERR(Debug::PAINTING, __func__ << ": Found new anchor pit = " << pit
|
LYXERR0(__func__ << ": Found new anchor pit = " << pit
|
||||||
<< " anchor ypos = " << pm.position()
|
<< " anchor ypos = " << pm.position()
|
||||||
<< " (was " << d->anchor_pit_ << ", " << d->anchor_ypos_ << ")");
|
<< " (was " << d->anchor_pit_ << ", " << d->anchor_ypos_ << ")"
|
||||||
|
"\nIf you see this message, please report.");
|
||||||
d->anchor_pit_ = pit;
|
d->anchor_pit_ = pit;
|
||||||
d->anchor_ypos_ = pm.position();
|
d->anchor_ypos_ = pm.position();
|
||||||
break;
|
break;
|
||||||
|
@ -216,6 +216,56 @@ void TextMetrics::newParMetricsUp()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TextMetrics::updateMetrics(pit_type const anchor_pit, int const anchor_ypos,
|
||||||
|
int const bv_height)
|
||||||
|
{
|
||||||
|
LASSERT(text_->isMainText(), return);
|
||||||
|
pit_type const npit = pit_type(text_->paragraphs().size());
|
||||||
|
|
||||||
|
if (!contains(anchor_pit))
|
||||||
|
// Rebreak anchor paragraph.
|
||||||
|
redoParagraph(anchor_pit);
|
||||||
|
ParagraphMetrics & anchor_pm = parMetrics(anchor_pit);
|
||||||
|
anchor_pm.setPosition(anchor_ypos);
|
||||||
|
|
||||||
|
// Redo paragraphs above anchor if necessary.
|
||||||
|
int y1 = anchor_ypos - anchor_pm.ascent();
|
||||||
|
// We are now just above the anchor paragraph.
|
||||||
|
pit_type pit1 = anchor_pit - 1;
|
||||||
|
for (; pit1 >= 0 && y1 > 0; --pit1) {
|
||||||
|
if (!contains(pit1))
|
||||||
|
redoParagraph(pit1);
|
||||||
|
ParagraphMetrics & pm = parMetrics(pit1);
|
||||||
|
y1 -= pm.descent();
|
||||||
|
// Save the paragraph position in the cache.
|
||||||
|
pm.setPosition(y1);
|
||||||
|
y1 -= pm.ascent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redo paragraphs below the anchor if necessary.
|
||||||
|
int y2 = anchor_ypos + anchor_pm.descent();
|
||||||
|
// We are now just below the anchor paragraph.
|
||||||
|
pit_type pit2 = anchor_pit + 1;
|
||||||
|
for (; pit2 < npit && y2 < bv_height; ++pit2) {
|
||||||
|
if (!contains(pit2))
|
||||||
|
redoParagraph(pit2);
|
||||||
|
ParagraphMetrics & pm = parMetrics(pit2);
|
||||||
|
y2 += pm.ascent();
|
||||||
|
// Save the paragraph position in the cache.
|
||||||
|
pm.setPosition(y2);
|
||||||
|
y2 += pm.descent();
|
||||||
|
}
|
||||||
|
|
||||||
|
LYXERR(Debug::PAINTING, "TextMetrics::updateMetrics "
|
||||||
|
<< " anchor pit = " << anchor_pit
|
||||||
|
<< " anchor ypos = " << anchor_ypos
|
||||||
|
<< " y1 = " << y1
|
||||||
|
<< " y2 = " << y2
|
||||||
|
<< " pit1 = " << pit1
|
||||||
|
<< " pit2 = " << pit2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TextMetrics::metrics(MetricsInfo const & mi, Dimension & dim, int min_width)
|
bool TextMetrics::metrics(MetricsInfo const & mi, Dimension & dim, int min_width)
|
||||||
{
|
{
|
||||||
LBUFERR(mi.base.textwidth > 0);
|
LBUFERR(mi.base.textwidth > 0);
|
||||||
|
@ -73,6 +73,10 @@ public:
|
|||||||
///
|
///
|
||||||
void newParMetricsUp();
|
void newParMetricsUp();
|
||||||
|
|
||||||
|
/// Update metrics up to \c bv_height. Only usable for main text (for now).
|
||||||
|
void updateMetrics(pit_type const anchor_pit, int const anchor_ypos,
|
||||||
|
int const bv_height);
|
||||||
|
|
||||||
/// compute text metrics.
|
/// compute text metrics.
|
||||||
bool metrics(MetricsInfo const & mi, Dimension & dim, int min_width = 0);
|
bool metrics(MetricsInfo const & mi, Dimension & dim, int min_width = 0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user