X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FBufferView.cpp;h=e31efcf673d433a52ab8efef42dca41d8335cb33;hb=cf14e814124ccbc8155fa1dde98d03be319c0e87;hp=35a126b18ac6e87bb6e4240f34f999b146554f4b;hpb=a04b5c3965faf79d534f0090712d3e47cebc46ab;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 35a126b18a..e31efcf673 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -110,7 +110,7 @@ T * getInsetByCode(Cursor const & cur, InsetCode code) Inset * inset = it.nextInset(); if (inset && inset->lyxCode() == code) return static_cast(inset); - return 0; + return nullptr; } @@ -233,14 +233,11 @@ struct BufferView::Private Private(BufferView & bv) : update_strategy_(FullScreenUpdate), update_flags_(Update::Force), - wh_(0), cursor_(bv), - anchor_pit_(0), anchor_ypos_(0), - inlineCompletionUniqueChars_(0), - last_inset_(0), clickable_inset_(false), - mouse_position_cache_(), - bookmark_edit_position_(-1), gui_(0), - horiz_scroll_offset_(0), - caret_ascent_(0), caret_descent_(0) + cursor_(bv), anchor_pit_(0), anchor_ypos_(0), + wh_(0), inlineCompletionUniqueChars_(0), + last_inset_(nullptr), mouse_position_cache_(), + gui_(nullptr), bookmark_edit_position_(-1), + horiz_scroll_offset_(0), clickable_inset_(false) { xsel_cache_.set = false; } @@ -253,9 +250,10 @@ struct BufferView::Private Update::flags update_flags_; /// CoordCache coord_cache_; + /// + typedef map MathRows; + MathRows math_rows_; - /// Estimated average par height for scrollbar. - int wh_; /// this is used to handle XSelection events in the right manner. struct { CursorSlice cursor; @@ -268,6 +266,8 @@ struct BufferView::Private pit_type anchor_pit_; /// int anchor_ypos_; + /// Estimated average par height for scrollbar. + int wh_; /// vector par_height_; @@ -286,17 +286,12 @@ struct BufferView::Private * Not owned, so don't delete. */ Inset const * last_inset_; - /// are we hovering something that we can click - bool clickable_inset_; /// position of the mouse at the time of the last mouse move /// This is used to update the hovering status of inset in /// cases where the buffer is scrolled, but the mouse didn't move. Point mouse_position_cache_; - // cache for id of the paragraph which was edited the last time - int bookmark_edit_position_; - mutable TextMetricsCache text_metrics_; /// Whom to notify. @@ -312,19 +307,15 @@ struct BufferView::Private /// 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_; + int horiz_scroll_offset_; /// a slice pointing to the start of the row where the cursor /// is (at last draw time) CursorSlice current_row_slice_; - /// a slice pointing to the start of the row where cursor was - /// at previous draw event - CursorSlice last_row_slice_; - - // The vertical size of the blinking caret. Only used for math - // Using it for text could be bad when undo restores the cursor - // current font, since the caret size could become wrong. - int caret_ascent_; - int caret_descent_; + /// are we hovering something that we can click + bool clickable_inset_; }; @@ -352,9 +343,10 @@ BufferView::~BufferView() // That is to say, if a cursor is in a nested inset, it will be // restore to the left of the top level inset. LastFilePosSection::FilePos fp; + fp.file = buffer_.fileName(); fp.pit = d->cursor_.bottom().pit(); fp.pos = d->cursor_.bottom().pos(); - theSession().lastFilePos().save(buffer_.fileName(), fp); + theSession().lastFilePos().save(fp); if (d->last_inset_) d->last_inset_->setMouseHover(this, false); @@ -440,6 +432,20 @@ CoordCache const & BufferView::coordCache() const } +MathRow const & BufferView::mathRow(MathData const * cell) const +{ + auto it = d->math_rows_.find(cell); + LATTEST(it != d->math_rows_.end()); + return it->second; +} + + +void BufferView::setMathRow(MathData const * cell, MathRow const & mrow) +{ + d->math_rows_[cell] = mrow; +} + + Buffer & BufferView::buffer() { return buffer_; @@ -500,11 +506,6 @@ void BufferView::processUpdateFlags(Update::flags flags) */ buffer_.updateMacros(); - // SinglePar is ignored for now (this should probably change). We - // set it ourselves below, at the price of always rebreaking the - // paragraph at cursor. This can be expensive for large tables. - flags = flags & ~Update::SinglePar; - // First check whether the metrics and inset positions should be updated if (flags & Update::Force) { // This will update the CoordCache items and replace Force @@ -512,20 +513,25 @@ void BufferView::processUpdateFlags(Update::flags flags) updateMetrics(flags); } - // Detect whether we can only repaint a single paragraph. + // 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)) { - if (singleParUpdate()) - flags = flags | Update::SinglePar; - else + if (!(flags & Update::ForceDraw) + && (flags & Update::SinglePar) + && !singleParUpdate()) updateMetrics(flags); - } // Then make sure that the screen contains the cursor if needed if (flags & Update::FitCursor) { if (needsFitCursor()) { - scrollToCursor(d->cursor_, false); + // First try to make the selection start visible + // (which is just the cursor when there is no selection) + scrollToCursor(d->cursor_.selectionBegin(), 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); // Metrics have to be recomputed (maybe again) updateMetrics(flags); } @@ -538,7 +544,7 @@ void BufferView::processUpdateFlags(Update::flags flags) LYXERR(Debug::PAINTING, "Cumulative flags: " << flagsAsString(flags)); // Now compute the update strategy - // Possibly values in flag are None, Decoration, ForceDraw + // Possibly values in flag are None, SinglePar, Decoration, ForceDraw LATTEST((d->update_flags_ & ~(Update::None | Update::SinglePar | Update::Decoration | Update::ForceDraw)) == 0); @@ -1258,7 +1264,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) Inset * BufferView::editedInset(string const & name) const { map::const_iterator it = d->edited_insets_.find(name); - return it == d->edited_insets_.end() ? 0 : it->second; + return it == d->edited_insets_.end() ? nullptr : it->second; } @@ -1531,12 +1537,18 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_CHANGE_NEXT: findNextChange(this); + if (cur.inset().isTable()) + // In tables, there might be whole changed rows or columns + cur.dispatch(cmd); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); break; case LFUN_CHANGE_PREVIOUS: findPreviousChange(this); + if (cur.inset().isTable()) + // In tables, there might be whole changed rows or columns + cur.dispatch(cmd); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); break; @@ -1549,32 +1561,43 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } break; - case LFUN_ALL_CHANGES_ACCEPT: + case LFUN_ALL_CHANGES_ACCEPT: { // select complete document cur.reset(); cur.selHandle(true); buffer_.text().cursorBottom(cur); // accept everything in a single step to support atomic undo + // temporarily disable track changes in order to end with really + // no new (e.g., DPSM-caused) changes (see #7487) + bool const track = buffer_.params().track_changes; + buffer_.params().track_changes = false; buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT); + buffer_.params().track_changes = track; cur.resetAnchor(); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); break; + } - case LFUN_ALL_CHANGES_REJECT: + case LFUN_ALL_CHANGES_REJECT: { // select complete document cur.reset(); cur.selHandle(true); buffer_.text().cursorBottom(cur); // reject everything in a single step to support atomic undo - // Note: reject does not work recursively; the user may have to repeat the operation + // temporarily disable track changes in order to end with really + // no new (e.g., DPSM-caused) changes (see #7487) + bool const track = buffer_.params().track_changes; + buffer_.params().track_changes = false; buffer_.text().acceptOrRejectChanges(cur, Text::REJECT); + buffer_.params().track_changes = track; cur.resetAnchor(); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); break; + } case LFUN_WORD_FIND_FORWARD: case LFUN_WORD_FIND_BACKWARD: { @@ -2181,7 +2204,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } -docstring const BufferView::requestSelection() +docstring BufferView::requestSelection() { Cursor & cur = d->cursor_; @@ -2238,7 +2261,7 @@ Inset const * BufferView::getCoveringInset(Text const & text, TextMetrics & tm = d->text_metrics_[&text]; Inset * inset = tm.checkInsetHit(x, y); if (!inset) - return 0; + return nullptr; if (!inset->descendable(*this)) // No need to go further down if the inset is not @@ -2279,7 +2302,7 @@ void BufferView::updateHoveredInset() const if (d->last_inset_) { // Remove the hint on the last hovered inset (if any). need_redraw |= d->last_inset_->setMouseHover(this, false); - d->last_inset_ = 0; + d->last_inset_ = nullptr; } if (covering_inset && covering_inset->setMouseHover(this, true)) { @@ -2310,7 +2333,7 @@ void BufferView::clearLastInset(Inset * inset) const LYXERR0("Wrong last_inset!"); LATTEST(false); } - d->last_inset_ = 0; + d->last_inset_ = nullptr; } @@ -2551,8 +2574,9 @@ TextMetrics & BufferView::textMetrics(Text const * t) LBUFERR(t); TextMetricsCache::iterator tmc_it = d->text_metrics_.find(t); if (tmc_it == d->text_metrics_.end()) { - tmc_it = d->text_metrics_.insert( - make_pair(t, TextMetrics(this, const_cast(t)))).first; + tmc_it = d->text_metrics_.emplace(std::piecewise_construct, + std::forward_as_tuple(t), + std::forward_as_tuple(this, const_cast(t))).first; } return tmc_it->second; } @@ -2786,6 +2810,7 @@ void BufferView::updateMetrics(Update::flags & update_flags) // 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 @@ -2883,7 +2908,7 @@ void BufferView::updatePosCache() } -void BufferView::insertLyXFile(FileName const & fname) +void BufferView::insertLyXFile(FileName const & fname, bool const ignorelang) { LASSERT(d->cursor_.inTexted(), return); @@ -2901,8 +2926,12 @@ void BufferView::insertLyXFile(FileName const & fname) ErrorList & el = buffer_.errorList("Parse"); // Copy the inserted document error list into the current buffer one. el = buf.errorList("Parse"); + ParagraphList & pars = buf.paragraphs(); + if (ignorelang) + // set main language of imported file to context language + buf.changeLanguage(buf.language(), d->cursor_.getFont().language()); buffer_.undo().recordUndo(d->cursor_); - cap::pasteParagraphList(d->cursor_, buf.paragraphs(), + cap::pasteParagraphList(d->cursor_, pars, buf.params().documentClassPtr(), el); res = _("Document %1$s inserted."); } else { @@ -3017,20 +3046,14 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const } -void BufferView::setCaretAscentDescent(int asc, int des) -{ - d->caret_ascent_ = asc; - d->caret_descent_ = des; -} - - void BufferView::caretPosAndHeight(Point & p, int & h) const { int asc, des; Cursor const & cur = cursor(); if (cur.inMathed()) { - asc = d->caret_ascent_; - des = d->caret_descent_; + MathRow const & mrow = mathRow(&cur.cell()); + asc = mrow.caret_ascent; + des = mrow.caret_descent; } else { Font const font = cur.real_current_font; frontend::FontMetrics const & fm = theFontMetrics(font); @@ -3043,11 +3066,16 @@ void BufferView::caretPosAndHeight(Point & p, int & h) const } -bool BufferView::cursorInView(Point const & p, int h) const +bool BufferView::caretInView() const { - Cursor const & cur = cursor(); + if (!paragraphVisible(cursor())) + return false; + Point p; + int h; + caretPosAndHeight(p, h); + // does the cursor touch the screen ? - if (p.y_ + h < 0 || p.y_ >= workHeight() || !paragraphVisible(cur)) + if (p.y_ + h < 0 || p.y_ >= workHeight()) return false; return true; } @@ -3072,30 +3100,24 @@ int BufferView::horizScrollOffset(Text const * text, } -bool BufferView::hadHorizScrollOffset(Text const * text, - pit_type pit, pos_type pos) const -{ - return !d->last_row_slice_.empty() - && &text->inset() == d->last_row_slice_.inset().asInsetText() - && pit == d->last_row_slice_.pit() - && pos == d->last_row_slice_.pos(); -} - - void BufferView::setCurrentRowSlice(CursorSlice const & rowSlice) { // nothing to do if the cursor was already on this row - if (d->current_row_slice_ == rowSlice) { - d->last_row_slice_ = CursorSlice(); + if (d->current_row_slice_ == rowSlice) return; - } // if the (previous) current row was scrolled, we have to // remember it in order to repaint it next time. - if (d->horiz_scroll_offset_ != 0) - d->last_row_slice_ = d->current_row_slice_; - else - d->last_row_slice_ = CursorSlice(); + if (d->horiz_scroll_offset_ != 0) { + // search the old row in cache and mark it changed + for (auto & tm_pair : d->text_metrics_) { + if (&tm_pair.first->inset() == rowSlice.inset().asInsetText()) { + tm_pair.second.setRowChanged(rowSlice.pit(), rowSlice.pos()); + // We found it, no need to continue. + break; + } + } + } // Since we changed row, the scroll offset is not valid anymore d->horiz_scroll_offset_ = 0; @@ -3152,8 +3174,7 @@ void BufferView::checkCursorScrollOffset() << d->horiz_scroll_offset_ << " to " << offset); if (d->update_strategy_ == NoScreenUpdate - && (offset != d->horiz_scroll_offset_ - || !d->last_row_slice_.empty())) { + && offset != d->horiz_scroll_offset_) { // FIXME: if one uses SingleParUpdate, then home/end // will not work on long rows. Why? d->update_strategy_ = FullScreenUpdate; @@ -3185,7 +3206,6 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // however, the different coordinates of insets and paragraphs // needs to be updated. LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate"); - pi.full_repaint = false; if (pain.isNull()) { pi.full_repaint = true; tm.draw(pi, 0, y);