X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=023301dd482e596d77e674ac597d9a022288304f;hb=bfe98181169d9e697e515da974d9b6a15a06c940;hp=f9bbe234c66c7d77829cd5b49277ef6cff439a56;hpb=4671214f3dbc95207eda7cafb37cd0064b11f3e8;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index f9bbe234c6..023301dd48 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -171,18 +171,18 @@ bool findInset(DocIterator & dit, vector const & codes, /// Moves cursor to the next inset with one of the given codes. -void gotoInset(BufferView * bv, vector const & codes, +bool gotoInset(BufferView * bv, vector const & codes, bool same_content) { Cursor tmpcur = bv->cursor(); if (!findInset(tmpcur, codes, same_content)) { bv->cursor().message(_("No more insets")); - return; + return false; } tmpcur.clearSelection(); bv->setCursor(tmpcur); - bv->showCursor(); + return bv->scrollToCursor(bv->cursor(), false, true); } @@ -228,7 +228,7 @@ struct BufferView::Private /// CoordCache coord_cache_; /// - typedef map MathRows; + typedef unordered_map MathRows; MathRows math_rows_; /// this is used to handle XSelection events in the right manner. @@ -331,16 +331,20 @@ BufferView::~BufferView() } -int BufferView::rightMargin() const +int BufferView::defaultMargin() const { // The value used to be hardcoded to 10 - int const default_margin = zoomedPixels(10); + return zoomedPixels(20); +} + + +int BufferView::rightMargin() const +{ // The additional test for the case the outliner is opened. - if (!full_screen_ || !lyxrc.full_screen_limit - || width_ < lyxrc.full_screen_width + 2 * default_margin) - return default_margin; + if (full_screen_ && lyxrc.full_screen_limit) + return max(defaultMargin(), (width_ - lyxrc.full_screen_width) / 2); - return (width_ - lyxrc.full_screen_width) / 2; + return defaultMargin(); } @@ -537,13 +541,13 @@ void BufferView::processUpdateFlags(Update::flags flags) 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); + scrollToCursor(d->cursor_.selectionBegin(), false, false); // Metrics have to be recomputed (maybe again) updateMetrics(); // 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); + scrollToCursor(d->cursor_, false, false); // Metrics have to be recomputed (maybe again) updateMetrics(flags); } @@ -579,7 +583,7 @@ void BufferView::processUpdateFlags(Update::flags flags) } -void BufferView::updateScrollbar() +void BufferView::updateScrollbarParameters() { if (height_ == 0 && width_ == 0) return; @@ -737,7 +741,7 @@ void BufferView::scrollDocView(int const pixels, bool update) // cut off at the top if (pixels <= d->scrollbarParameters_.min) { DocIterator dit = doc_iterator_begin(&buffer_); - showCursor(dit, false, update); + showCursor(dit, false, false, update); LYXERR(Debug::SCROLLING, "scroll to top"); return; } @@ -746,7 +750,7 @@ void BufferView::scrollDocView(int const pixels, bool update) if (pixels >= d->scrollbarParameters_.max) { DocIterator dit = doc_iterator_end(&buffer_); dit.backwardPos(); - showCursor(dit, false, update); + showCursor(dit, false, false, update); LYXERR(Debug::SCROLLING, "scroll to bottom"); return; } @@ -771,7 +775,7 @@ void BufferView::scrollDocView(int const pixels, bool update) DocIterator dit = doc_iterator_begin(&buffer_); dit.pit() = i; LYXERR(Debug::SCROLLING, "pixels = " << pixels << " -> scroll to pit " << i); - showCursor(dit, false, update); + showCursor(dit, false, false, update); } @@ -957,32 +961,25 @@ int BufferView::workWidth() const void BufferView::recenter() { - showCursor(d->cursor_, true, true); + showCursor(d->cursor_, true, false, true); } void BufferView::showCursor() { - showCursor(d->cursor_, false, true); + showCursor(d->cursor_, false, false, true); } void BufferView::showCursor(DocIterator const & dit, - bool recenter, bool update) -{ - if (scrollToCursor(dit, recenter) && update) - processUpdateFlags(Update::Force); -} - - -void BufferView::scrollToCursor() + bool recenter, bool force, bool update) { - if (scrollToCursor(d->cursor_, false)) + if (scrollToCursor(dit, recenter, force) && update) processUpdateFlags(Update::Force); } -bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter) +bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter, bool force) { // We are not properly started yet, delay until resizing is done. if (height_ == 0) @@ -1010,7 +1007,7 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter) else if (bot_pit == tm.last().first + 1) tm.newParMetricsDown(); - if (tm.contains(bot_pit)) { + if (tm.contains(bot_pit) && !force) { ParagraphMetrics const & pm = tm.parMetrics(bot_pit); LBUFERR(!pm.rows().empty()); // FIXME: smooth scrolling doesn't work in mathed. @@ -1074,9 +1071,9 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool const recenter) else if (d->anchor_pit_ == max_pit) d->anchor_ypos_ = height_ - offset - row_dim.descent(); else if (offset > height_) - d->anchor_ypos_ = height_ - offset - defaultRowHeight(); + d->anchor_ypos_ = height_ - offset - row_dim.descent(); else - d->anchor_ypos_ = defaultRowHeight() * 2; + d->anchor_ypos_ = row_dim.ascent(); return true; } @@ -1484,6 +1481,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) else { dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); + resetInlineCompletionPos(); if (buffer().params().citeEngine() != engine || buffer().params().citeEngineType() != enginetype) buffer().invalidateCiteLabels(); @@ -1504,6 +1502,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) else { dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); + resetInlineCompletionPos(); if (buffer().params().citeEngine() != engine || buffer().params().citeEngineType() != enginetype) buffer().invalidateCiteLabels(); @@ -1582,8 +1581,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) success = setCursorFromEntries({id, pos}, {id_end, pos_end}); } - if (success) - dr.screenUpdate(Update::Force | Update::FitCursor); + if (success && scrollToCursor(d->cursor_, false, true)) + dr.screenUpdate(Update::Force); } else { // Switch to other buffer view and resend cmd lyx::dispatch(FuncRequest( @@ -1596,19 +1595,13 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } case LFUN_NOTE_NEXT: - gotoInset(this, { NOTE_CODE }, false); - // FIXME: if SinglePar is changed to act on the inner - // paragraph, this will not be OK anymore. The update is - // useful for auto-open collapsible insets. - dr.screenUpdate(Update::SinglePar | Update::FitCursor); + if (gotoInset(this, { NOTE_CODE }, false)) + dr.screenUpdate(Update::Force); break; case LFUN_REFERENCE_NEXT: { - gotoInset(this, { LABEL_CODE, REF_CODE }, true); - // FIXME: if SinglePar is changed to act on the inner - // paragraph, this will not be OK anymore. The update is - // useful for auto-open collapsible insets. - dr.screenUpdate(Update::SinglePar | Update::FitCursor); + if (gotoInset(this, { LABEL_CODE, REF_CODE }, true)) + dr.screenUpdate(Update::Force); break; } @@ -1916,7 +1909,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) cur.setCursor(doc_iterator_begin(cur.buffer())); cur.selHandle(false); // Force an immediate computation of metrics because we need it below - updateMetrics(); + if (scrolled) + processUpdateFlags(Update::Force); d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_, true, act == LFUN_SCREEN_UP); @@ -2072,21 +2066,22 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // an arbitrary number to limit number of iterations const int max_iter = 100000; int iterations = 0; - Cursor & curs = d->cursor_; - Cursor const savecur = curs; - curs.reset(); - if (!curs.nextInset()) - curs.forwardInset(); - curs.beginUndoGroup(); - while(curs && iterations < max_iter) { - Inset * const ins = curs.nextInset(); + Cursor & bvcur = d->cursor_; + Cursor const savecur = bvcur; + bvcur.reset(); + if (!bvcur.nextInset()) + bvcur.forwardInset(); + bvcur.beginUndoGroup(); + while(bvcur && iterations < max_iter) { + Inset * const ins = bvcur.nextInset(); if (!ins) break; docstring insname = ins->layoutName(); while (!insname.empty()) { if (insname == name || name == from_utf8("*")) { - curs.recordUndo(); lyx::dispatch(fr, dr); + // we do not want to remember selection here + bvcur.clearSelection(); ++iterations; break; } @@ -2096,11 +2091,11 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) insname = insname.substr(0, i); } // if we did not delete the inset, skip it - if (!curs.nextInset() || curs.nextInset() == ins) - curs.forwardInset(); + if (!bvcur.nextInset() || bvcur.nextInset() == ins) + bvcur.forwardInset(); } - curs = savecur; - curs.fixIfBroken(); + bvcur = savecur; + bvcur.fixIfBroken(); /** This is a dummy undo record only to remember the cursor * that has just been set; this will be used on a redo action * (see ticket #10097) @@ -2108,8 +2103,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) * FIXME: a better fix would be to have a way to set the * cursor value directly, but I am not sure it is worth it. */ - curs.recordUndo(); - curs.endUndoGroup(); + bvcur.recordUndo(); + bvcur.endUndoGroup(); dr.screenUpdate(Update::Force); dr.forceBufferUpdate(); @@ -2383,12 +2378,50 @@ Inset const * BufferView::getCoveringInset(Text const & text, } +Inset const * BufferView::clickableMathInset(InsetMathNest const * inset, + CoordCache::Insets const & inset_cache, int x, int y) const +{ + for (size_t i = 0; i < inset->nargs(); ++i) { + MathData const & ar = inset->cell(i); + for (size_t j = 0; j < ar.size(); ++j) { + string const name = lyxerr.debugging(Debug::MATHED) + ? insetName(ar[j].nucleus()->lyxCode()) + : string(); + LYXERR(Debug::MATHED, "Checking inset: " << name); + if (ar[j].nucleus()->clickable(*this, x, y)) { + if (inset_cache.covers(ar[j].nucleus(), x, y)) { + LYXERR(Debug::MATHED, "Clickable inset: " + << name); + return ar[j].nucleus(); + } + } + InsetMathNest const * imn = + ar[j].nucleus()->asNestInset(); + if (imn) { + Inset const * inner = + clickableMathInset(imn, inset_cache, x, y); + if (inner) + return inner; + } + } + } + return nullptr; +} + + void BufferView::updateHoveredInset() const { // Get inset under mouse, if there is one. int const x = d->mouse_position_cache_.x_; int const y = d->mouse_position_cache_.y_; Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y); + if (covering_inset && covering_inset->asInsetMath()) { + Inset const * inner_inset = clickableMathInset( + covering_inset->asInsetMath()->asNestInset(), + coordCache().getInsets(), x, y); + if (inner_inset) + covering_inset = inner_inset; + } d->clickable_inset_ = covering_inset && covering_inset->clickable(*this, x, y); @@ -3159,6 +3192,8 @@ void BufferView::caretPosAndDim(Point & p, Dimension & dim) const } else { Font const font = cur.real_current_font; frontend::FontMetrics const & fm = theFontMetrics(font); + // lineWidth() can be 0 to mean 'thin line' on HiDpi, but the + // caret drawing code is not prepared for that. dim.wid = max(fm.lineWidth(), 1); dim.asc = fm.maxAscent(); dim.des = fm.maxDescent(); @@ -3357,15 +3392,12 @@ void BufferView::checkCursorScrollOffset() //lyxerr << "cur_x=" << cur_x << ", offset=" << offset << ", row.wid=" << row.width() << ", margin=" << MARGIN << endl; - if (offset != d->horiz_scroll_offset_) + if (offset != d->horiz_scroll_offset_) { LYXERR(Debug::PAINTING, "Horiz. scroll offset changed from " << d->horiz_scroll_offset_ << " to " << offset); - - if (d->update_strategy_ == NoScreenUpdate - && offset != d->horiz_scroll_offset_) { - // FIXME: if one uses SingleParUpdate, then home/end - // will not work on long rows. Why? - d->update_strategy_ = FullScreenUpdate; + row.changed(true); + if (d->update_strategy_ == NoScreenUpdate) + d->update_strategy_ = SingleParUpdate; } d->horiz_scroll_offset_ = offset; @@ -3450,7 +3482,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // The scrollbar needs an update. // FIXME: does it always? see ticket #11947. - updateScrollbar(); + updateScrollbarParameters(); // Normalize anchor for next time pair firstpm = tm.first();