diff --git a/src/BufferView.C b/src/BufferView.C index a5f7956928..d1d768ac36 100644 --- a/src/BufferView.C +++ b/src/BufferView.C @@ -339,7 +339,7 @@ bool BufferView::multiParSel() } -bool BufferView::update(Update::flags flags) +std::pair BufferView::update(Update::flags flags) { // This is close to a hot-path. if (lyxerr.debugging(Debug::DEBUG)) { @@ -353,7 +353,7 @@ bool BufferView::update(Update::flags flags) // Check needed to survive LyX startup if (!buffer_) - return false; + return make_pair(false, false); if (lyxerr.debugging(Debug::WORKAREA)) { lyxerr[Debug::WORKAREA] << "BufferView::update" << std::endl; @@ -362,15 +362,31 @@ bool BufferView::update(Update::flags flags) // Update macro store buffer_->buildMacros(); - // First drawing step - updateMetrics(flags & Update::SinglePar); - + // Now do the first drawing step if needed. This consists on updating + // the CoordCache in updateMetrics(). // The second drawing step is done in WorkArea::redraw() if needed. - bool const need_second_step = - (flags & (Update::SinglePar | Update::Force | Update::FitCursor | Update::MultiParSel)) - && (fitCursor() || multiParSel()); - return need_second_step; + // Case when no explicit update is requested. + if (!(flags & (Update::SinglePar | Update::Force))) { + if (fitCursor() || multiParSel()) { + // a CoordCache update is needed + updateMetrics(false); + // tell the frontend to update the screen. + return make_pair(true, false); + } + // no need to do anything. + return make_pair(false, false); + } + + // We are now in the case (Update::SinglePar | Update::Force) + bool single_par = flags & Update::SinglePar; + updateMetrics(single_par); + + // Don't forget to do check for fitCursor() and multiParSel(). + fitCursor(); + multiParSel(); + + return make_pair(true, single_par); } @@ -1006,7 +1022,7 @@ void BufferView::workAreaResize(int width, int height) } -bool BufferView::workAreaDispatch(FuncRequest const & cmd0) +std::pair BufferView::workAreaDispatch(FuncRequest const & cmd0) { //lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl; @@ -1016,14 +1032,11 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // E.g. Qt mouse press when no buffer if (!buffer_) - return false; - - bool needRedraw = false; + return make_pair(false, false); LCursor cur(*this); cur.push(buffer_->inset()); cur.selection() = cursor_.selection(); - needRedraw |= cur.selection(); // Either the inset under the cursor or the // surrounding LyXText will handle this event. @@ -1046,7 +1059,6 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // cur.bv().cursor() = cur; (or similar) if (inset) { inset->dispatch(cur, cmd); - needRedraw = true; } // Now dispatch to the temporary cursor. If the real cursor should @@ -1054,17 +1066,12 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) if (!cur.result().dispatched()) cur.dispatch(cmd); - if (cur.result().dispatched()) { - // Redraw if requested or necessary. - if (cur.result().update()) - needRedraw |= update(Update::FitCursor | Update::Force); - else - needRedraw |= update(Update::FitCursor | Update::MultiParSel); - } + // Redraw if requested and necessary. + if (cur.result().dispatched() && cur.result().update()) + return update(cur.result().update()); // When the above and the inner function are fixed, we can do this: - //return needRedraw; - return true; + return make_pair(false, false); } @@ -1217,7 +1224,7 @@ ViewMetricsInfo const & BufferView::viewMetricsInfo() void BufferView::updateMetrics(bool singlepar) { // Clear out the position cache in case of full screen redraw. - //if (!singlepar) + if (!singlepar) coord_cache_.clear(); LyXText & buftext = buffer_->text(); diff --git a/src/BufferView.h b/src/BufferView.h index 7042440fdb..0e5f9102b0 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -97,9 +98,11 @@ public: * to do a fitcursor, and to force an update if screen * position changes. \c forceupdate means to force an update * in any case. - * \return true if a full updateMetrics() is needed. + * \retval (false, xxx) if no redraw is required + * \retval (true, true) if a single paragraph redraw is needed + * \retval (true, false) if a full redraw is needed */ - bool update(Update::flags flags = Update::FitCursor | Update::Force); + std::pair update(Update::flags flags = Update::FitCursor | Update::Force); /// move the screen to fit the cursor. /// Only to be called with good y coordinates (after a bv::metrics) @@ -167,8 +170,10 @@ public: /// dispatch method helper for \c WorkArea /// \sa WorkArea - /// \return true if a full redraw is needed - bool workAreaDispatch(FuncRequest const & ev); + /// \retval (false, xxx) if no redraw is required + /// \retval (true, true) if a single paragraph redraw is needed + /// \retval (true, false) if a full redraw is needed + std::pair workAreaDispatch(FuncRequest const & ev); /// access to anchor. pit_type anchor_ref() const; diff --git a/src/frontends/WorkArea.C b/src/frontends/WorkArea.C index 3deac37bd8..c2b8faf25c 100644 --- a/src/frontends/WorkArea.C +++ b/src/frontends/WorkArea.C @@ -191,7 +191,7 @@ void WorkArea::dispatch(FuncRequest const & cmd0) theLyXFunc().setLyXView(&lyx_view_); - bool needRedraw = buffer_view_->workAreaDispatch(cmd0); + std::pair needRedraw = buffer_view_->workAreaDispatch(cmd0); // Skip these when selecting if (cmd0.action != LFUN_MOUSE_MOTION) { @@ -209,8 +209,8 @@ void WorkArea::dispatch(FuncRequest const & cmd0) hideCursor(); toggleCursor(); - if (needRedraw) - redraw(); + if (needRedraw.first) + redraw(needRedraw.second); } diff --git a/src/insets/insetcollapsable.C b/src/insets/insetcollapsable.C index 6c1f127dfc..3d4434aa79 100644 --- a/src/insets/insetcollapsable.C +++ b/src/insets/insetcollapsable.C @@ -293,6 +293,11 @@ void InsetCollapsable::doDispatch(LCursor & cur, FuncRequest & cmd) switch (cmd.action) { case LFUN_MOUSE_PRESS: + if (cmd.button() == mouse_button::button1 && hitButton(cmd)) { + cur.dispatched(); + cur.noUpdate(); + break; + } if (status() == Inlined) InsetText::doDispatch(cur, cmd); else if (status() == Open && !hitButton(cmd)) @@ -314,36 +319,35 @@ void InsetCollapsable::doDispatch(LCursor & cur, FuncRequest & cmd) case LFUN_MOUSE_RELEASE: if (cmd.button() == mouse_button::button3) { + // Open the Inset configuration dialog showInsetDialog(&cur.bv()); break; } - switch (status()) { - - case Collapsed: - //lyxerr << "InsetCollapsable::lfunMouseRelease 1" << endl; - setStatus(cur, Open); - edit(cur, true); - cur.bv().cursor() = cur; - break; - - case Open: { - if (hitButton(cmd)) { - //lyxerr << "InsetCollapsable::lfunMouseRelease 2" << endl; - setStatus(cur, Collapsed); - cur.bv().cursor() = cur; - } else { - //lyxerr << "InsetCollapsable::lfunMouseRelease 3" << endl; - InsetText::doDispatch(cur, cmd); - } - break; - } - - case Inlined: - //lyxerr << "InsetCollapsable::lfunMouseRelease 4" << endl; + if (status() == Inlined) { + // The mouse click has to be within the inset! InsetText::doDispatch(cur, cmd); break; } + + if (cmd.button() == mouse_button::button1 && hitButton(cmd)) { + // Left button is clicked, the user asks to toggle the inset + // visual state. + cur.dispatched(); + cur.updateFlags(Update::Force | Update::FitCursor); + if (status() == Collapsed) { + setStatus(cur, Open); + edit(cur, true); + } + else { + setStatus(cur, Collapsed); + } + cur.bv().cursor() = cur; + break; + } + + // The mouse click is within the opened inset. + InsetText::doDispatch(cur, cmd); break; case LFUN_INSET_TOGGLE: diff --git a/src/lyxfunc.C b/src/lyxfunc.C index 85dfc6cf55..7de71684d5 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -1715,15 +1715,11 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // Redraw screen unless explicitly told otherwise. // This also initializes the position cache for all insets // in (at least partially) visible top-level paragraphs. - bool needSecondUpdate = false; - if (updateFlags != Update::None) - needSecondUpdate = view()->update(updateFlags); - else - needSecondUpdate = view()->fitCursor(); + std::pair needSecondUpdate = view()->update(updateFlags); + + if (needSecondUpdate.first) + view()->buffer()->changed(needSecondUpdate.second); - if (needSecondUpdate || updateFlags != Update::None) { - view()->buffer()->changed(updateFlags & Update::SinglePar); - } lyx_view_->updateStatusBar(); // if we executed a mutating lfun, mark the buffer as dirty diff --git a/src/lyxtext.h b/src/lyxtext.h index fab70b78cf..5bf93d8278 100644 --- a/src/lyxtext.h +++ b/src/lyxtext.h @@ -96,7 +96,9 @@ public: /// Set font over selection paragraphs and rebreak. void setFont(LCursor & cur, LyXFont const &, bool toggleall = false); - /// rebreaks the given par + /// Rebreaks the given paragraph. + /// \retval true if a full screen redraw is needed. + /// \retval false if a single paragraph redraw is enough. bool redoParagraph(BufferView &, pit_type pit); /// returns pos in given par at given x coord diff --git a/src/text.C b/src/text.C index 40349eacb9..7ca49fe69e 100644 --- a/src/text.C +++ b/src/text.C @@ -1153,8 +1153,12 @@ void LyXText::breakParagraph(LCursor & cur, bool keep_layout) // Because of the mix between the model (the paragraph contents) and the // view (the paragraph breaking in rows, we have to do this here before // the setCursor() call below. - redoParagraph(cur.bv(), cpit); - redoParagraph(cur.bv(), cpit + 1); + bool changed_height = redoParagraph(cur.bv(), cpit); + changed_height |= redoParagraph(cur.bv(), cpit + 1); + if (changed_height) + // A singlePar update is not enough in this case. + cur.updateFlags(Update::Force); + // This check is necessary. Otherwise the new empty paragraph will // be deleted automatically. And it is more friendly for the user! @@ -1253,7 +1257,9 @@ void LyXText::insertChar(LCursor & cur, char_type c) // FIXME: Inserting a character has nothing to do with setting a cursor. // Because of the mix between the model (the paragraph contents) and the // view (the paragraph breaking in rows, we have to do this here. - redoParagraph(cur.bv(), cur.pit()); + if (redoParagraph(cur.bv(), cur.pit())) + // A singlePar update is not enough in this case. + cur.updateFlags(Update::Force); setCursor(cur, cur.pit(), cur.pos() + 1, false, cur.boundary()); charInserted(); } @@ -1671,13 +1677,16 @@ bool LyXText::erase(LCursor & cur) } else needsUpdate = dissolveInset(cur); - // Make sure the cursor is correct. Is this really needed? // FIXME: Inserting characters has nothing to do with setting a cursor. // Because of the mix between the model (the paragraph contents) // and the view (the paragraph breaking in rows, we have to do this // here before the setCursorIntern() call. if (needsUpdate) { - redoParagraph(cur.bv(), cur.pit()); + if (redoParagraph(cur.bv(), cur.pit())) + // A singlePar update is not enough in this case. + cur.updateFlags(Update::Force); + // Make sure the cursor is correct. Is this really needed? + // No, not really... at least not here! setCursorIntern(cur, cur.pit(), cur.pos()); } @@ -1786,7 +1795,9 @@ bool LyXText::backspace(LCursor & cur) // Because of the mix between the model (the paragraph contents) // and the view (the paragraph breaking in rows, we have to do this // here before the setCursor() call. - redoParagraph(cur.bv(), cur.pit()); + if (redoParagraph(cur.bv(), cur.pit())) + // A singlePar update is not enough in this case. + cur.updateFlags(Update::Force); setCursor(cur, cur.pit(), cur.pos(), false, cur.boundary()); return needsUpdate; @@ -1929,7 +1940,7 @@ bool LyXText::redoParagraph(BufferView & bv, pit_type const pit) dim.asc += par.rows()[0].ascent(); dim.des -= par.rows()[0].ascent(); - bool const same = dim == par.dim(); + bool const same = dim.height() == par.dim().height(); par.dim() = dim; //lyxerr << "redoParagraph: " << par.rows().size() << " rows\n"; diff --git a/src/text3.C b/src/text3.C index 00bb118d73..9fb01eda4f 100644 --- a/src/text3.C +++ b/src/text3.C @@ -305,6 +305,11 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) { lyxerr[Debug::ACTION] << "LyXText::dispatch: cmd: " << cmd << endl; + // FIXME: We use the update flag to indicates wether a singlePar or a + // full screen update is needed. We reset it here but shall we restore it + // at the end? + cur.noUpdate(); + BOOST_ASSERT(cur.text() == this); BufferView * bv = &cur.bv(); CursorSlice oldTopSlice = cur.top(); @@ -988,6 +993,11 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph")); } + if (cmd.button() == mouse_button::button1) { + needsUpdate = false; + cur.noUpdate(); + } + break; } @@ -1037,8 +1047,12 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) break; // finish selection - if (cmd.button() == mouse_button::button1) - theSelection().haveSelection(cur.selection()); + if (cmd.button() == mouse_button::button1) { + if (cur.selection()) + theSelection().haveSelection(cur.selection()); + needsUpdate = false; + cur.noUpdate(); + } bv->switchKeyMap(); break; @@ -1474,6 +1488,19 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) } needsUpdate |= (cur.pos() != cur.lastpos()) && cur.selection(); + + // FIXME: The cursor flag is reset two lines below + // so we need to check here if some of the LFUN did touch that. + // for now only LyXText::erase() and LyXText::backspace() do that. + // The plan is to verify all the LFUNs and then to remove this + // singleParUpdate boolean altogether. + if (cur.result().update() & Update::Force) { + singleParUpdate = false; + needsUpdate = true; + } + + // FIXME: the following code should go in favor of fine grained + // update flag treatment. if (singleParUpdate) // Inserting characters does not change par height if (cur.bottom().paragraph().dim().height() @@ -1485,10 +1512,11 @@ void LyXText::dispatch(LCursor & cur, FuncRequest & cmd) return; } else needsUpdate = true; + if (!needsUpdate && &oldTopSlice.inset() == &cur.inset() && oldTopSlice.idx() == cur.idx() - && !sel + && !sel // sel is a backup of cur.selection() at the biginning of the function. && !cur.selection()) cur.noUpdate(); else