* BufferView:
- update(): returns a pair of bools in order to inform for singlePar cases.
- workAreaDispatch(): ditto and simplify the logic by using cursor update flags.
* text.C
- breakParagraph(): change the cursor update flag as needed.
- insertChar(): ditto.
- erase(): ditto
- redoParagraph(): now returns true if there is a height change.
* text3.C: dispatch():
- initialize the cursor flag at the beginning
- LFUN_MOUSE_PRESS: no need to update.
- LFUN_MOUSE_RELEASE: ditto.
- add some FIXMEs and comments.
* LyXFunc::dispatch(): simplify the BufferView update.
* insets/insetcollapsable.C: clarify and simplify the logic in doDispatch().
* WorkArea::dispatch(): redraw only if needed.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@15958
a592a061-630c-0410-9148-
cb99ea01b6c8
-bool BufferView::update(Update::flags flags)
+std::pair<bool, bool> BufferView::update(Update::flags flags)
{
// This is close to a hot-path.
if (lyxerr.debugging(Debug::DEBUG)) {
{
// This is close to a hot-path.
if (lyxerr.debugging(Debug::DEBUG)) {
// Check needed to survive LyX startup
if (!buffer_)
// Check needed to survive LyX startup
if (!buffer_)
+ return make_pair(false, false);
if (lyxerr.debugging(Debug::WORKAREA)) {
lyxerr[Debug::WORKAREA] << "BufferView::update" << std::endl;
if (lyxerr.debugging(Debug::WORKAREA)) {
lyxerr[Debug::WORKAREA] << "BufferView::update" << std::endl;
// Update macro store
buffer_->buildMacros();
// 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.
// 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);
-bool BufferView::workAreaDispatch(FuncRequest const & cmd0)
+std::pair<bool, bool> BufferView::workAreaDispatch(FuncRequest const & cmd0)
{
//lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl;
{
//lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl;
// E.g. Qt mouse press when no buffer
if (!buffer_)
// 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();
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.
// Either the inset under the cursor or the
// surrounding LyXText will handle this event.
// cur.bv().cursor() = cur; (or similar)
if (inset) {
inset->dispatch(cur, cmd);
// cur.bv().cursor() = cur; (or similar)
if (inset) {
inset->dispatch(cur, cmd);
}
// Now dispatch to the temporary cursor. If the real cursor should
}
// Now dispatch to the temporary cursor. If the real cursor should
if (!cur.result().dispatched())
cur.dispatch(cmd);
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:
// When the above and the inner function are fixed, we can do this:
- //return needRedraw;
- return true;
+ return make_pair(false, false);
void BufferView::updateMetrics(bool singlepar)
{
// Clear out the position cache in case of full screen redraw.
void BufferView::updateMetrics(bool singlepar)
{
// Clear out the position cache in case of full screen redraw.
coord_cache_.clear();
LyXText & buftext = buffer_->text();
coord_cache_.clear();
LyXText & buftext = buffer_->text();
#include <boost/utility.hpp>
#include <boost/signal.hpp>
#include <boost/utility.hpp>
#include <boost/signal.hpp>
* to do a fitcursor, and to force an update if screen
* position changes. \c forceupdate means to force an update
* in any case.
* 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<bool, bool> 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)
/// move the screen to fit the cursor.
/// Only to be called with good y coordinates (after a bv::metrics)
/// dispatch method helper for \c WorkArea
/// \sa WorkArea
/// 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<bool, bool> workAreaDispatch(FuncRequest const & ev);
/// access to anchor.
pit_type anchor_ref() const;
/// access to anchor.
pit_type anchor_ref() const;
theLyXFunc().setLyXView(&lyx_view_);
theLyXFunc().setLyXView(&lyx_view_);
- bool needRedraw = buffer_view_->workAreaDispatch(cmd0);
+ std::pair<bool, bool> needRedraw = buffer_view_->workAreaDispatch(cmd0);
// Skip these when selecting
if (cmd0.action != LFUN_MOUSE_MOTION) {
// Skip these when selecting
if (cmd0.action != LFUN_MOUSE_MOTION) {
hideCursor();
toggleCursor();
hideCursor();
toggleCursor();
- if (needRedraw)
- redraw();
+ if (needRedraw.first)
+ redraw(needRedraw.second);
switch (cmd.action) {
case LFUN_MOUSE_PRESS:
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))
if (status() == Inlined)
InsetText::doDispatch(cur, cmd);
else if (status() == Open && !hitButton(cmd))
case LFUN_MOUSE_RELEASE:
if (cmd.button() == mouse_button::button3) {
case LFUN_MOUSE_RELEASE:
if (cmd.button() == mouse_button::button3) {
+ // Open the Inset configuration dialog
showInsetDialog(&cur.bv());
break;
}
showInsetDialog(&cur.bv());
break;
}
- switch (status()) {
-
- case Collapsed:
- //lyxerr << "InsetCollapsable::lfunMouseRelease 1" << endl;
- setStatus(cur, Open);
- edit(cur, true);
- cur.bv().cursor() = cur;
+ if (status() == Inlined) {
+ // The mouse click has to be within the inset!
+ InsetText::doDispatch(cur, cmd);
- case Open: {
- if (hitButton(cmd)) {
- //lyxerr << "InsetCollapsable::lfunMouseRelease 2" << endl;
+ 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);
setStatus(cur, Collapsed);
- cur.bv().cursor() = cur;
- } else {
- //lyxerr << "InsetCollapsable::lfunMouseRelease 3" << endl;
- InsetText::doDispatch(cur, cmd);
+ cur.bv().cursor() = cur;
- case Inlined:
- //lyxerr << "InsetCollapsable::lfunMouseRelease 4" << endl;
- InsetText::doDispatch(cur, cmd);
- break;
- }
+ // The mouse click is within the opened inset.
+ InsetText::doDispatch(cur, cmd);
break;
case LFUN_INSET_TOGGLE:
break;
case LFUN_INSET_TOGGLE:
// Redraw screen unless explicitly told otherwise.
// This also initializes the position cache for all insets
// in (at least partially) visible top-level paragraphs.
// 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<bool, bool> 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
lyx_view_->updateStatusBar();
// if we executed a mutating lfun, mark the buffer as dirty
/// Set font over selection paragraphs and rebreak.
void setFont(LCursor & cur, LyXFont const &, bool toggleall = false);
/// 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
bool redoParagraph(BufferView &, pit_type pit);
/// returns pos in given par at given x coord
// 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.
// 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!
// This check is necessary. Otherwise the new empty paragraph will
// be deleted automatically. And it is more friendly for the user!
// 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.
// 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();
}
setCursor(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
charInserted();
}
} else
needsUpdate = dissolveInset(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) {
// 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());
}
setCursorIntern(cur, cur.pit(), cur.pos());
}
// 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.
// 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;
setCursor(cur, cur.pit(), cur.pos(), false, cur.boundary());
return needsUpdate;
dim.asc += par.rows()[0].ascent();
dim.des -= par.rows()[0].ascent();
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";
par.dim() = dim;
//lyxerr << "redoParagraph: " << par.rows().size() << " rows\n";
{
lyxerr[Debug::ACTION] << "LyXText::dispatch: cmd: " << cmd << endl;
{
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();
BOOST_ASSERT(cur.text() == this);
BufferView * bv = &cur.bv();
CursorSlice oldTopSlice = cur.top();
lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
}
lyx::dispatch(FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph"));
}
+ if (cmd.button() == mouse_button::button1) {
+ needsUpdate = false;
+ cur.noUpdate();
+ }
+
break;
// finish selection
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;
bv->switchKeyMap();
break;
}
needsUpdate |= (cur.pos() != cur.lastpos()) && cur.selection();
}
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()
if (singleParUpdate)
// Inserting characters does not change par height
if (cur.bottom().paragraph().dim().height()
return;
} else
needsUpdate = true;
return;
} else
needsUpdate = true;
if (!needsUpdate
&& &oldTopSlice.inset() == &cur.inset()
&& oldTopSlice.idx() == cur.idx()
if (!needsUpdate
&& &oldTopSlice.inset() == &cur.inset()
&& oldTopSlice.idx() == cur.idx()
+ && !sel // sel is a backup of cur.selection() at the biginning of the function.
&& !cur.selection())
cur.noUpdate();
else
&& !cur.selection())
cur.noUpdate();
else