From 8a3f21cd297371cd71f236434d64f5c1671afbfa Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Tue, 2 Dec 2003 10:10:15 +0000 Subject: [PATCH] Smooth, controllable scrolling in the Qt frontend. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8178 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/qt2/ChangeLog | 11 +++++ src/frontends/qt2/QContentPane.C | 85 ++++++++++++++++++++++++++++++-- src/frontends/qt2/QContentPane.h | 32 ++++++++++++ 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/src/frontends/qt2/ChangeLog b/src/frontends/qt2/ChangeLog index 1cbb50a838..dd7e0ddc29 100644 --- a/src/frontends/qt2/ChangeLog +++ b/src/frontends/qt2/ChangeLog @@ -1,3 +1,14 @@ +2003-12-01 Angus Leeming + + * QContentPane.[Ch] (SyntheticMouseEvent): a new, helper struct. + (QContentPane): store an instance of SyntheticMouseEvent and + add a slot, generateSyntheticMouseEvent, that is invoked by the + SyntheticMouseEvent::timeout. + (mouseMoveEvent): initialize synthetic_mouse_event_ when the + mouse button is depressed and the cursor is outside of the work area. + (generateSyntheticMouseEvent): if the scrollbar value is different + from the cached value, then dispatch a 'synthetic' mouse event. + 2003-12-01 Jürgen Spitzmüller * QVSpace.C: remove VSPACE::NONE, remove restore button. diff --git a/src/frontends/qt2/QContentPane.C b/src/frontends/qt2/QContentPane.C index 43ac1e011c..c169dedab3 100644 --- a/src/frontends/qt2/QContentPane.C +++ b/src/frontends/qt2/QContentPane.C @@ -10,6 +10,8 @@ #include +#include + #include "QWorkArea.h" #include "QContentPane.h" #include "QLyXKeySym.h" @@ -18,9 +20,6 @@ #include #include -#include "funcrequest.h" - - namespace { /// return the LyX key state from Qt's @@ -74,10 +73,20 @@ mouse_button::state q_motion_state(Qt::ButtonState state) } // namespace anon +SyntheticMouseEvent::SyntheticMouseEvent() + : timeout(200), restart_timeout(true), + x_old(-1), y_old(-1), scrollbar_value_old(-1.0) +{} + + QContentPane::QContentPane(QWorkArea * parent) : QWidget(parent, "content_pane", WRepaintNoErase), track_scrollbar_(true), wa_(parent) { + synthetic_mouse_event_.timeout.timeout.connect( + boost::bind(&QContentPane::generateSyntheticMouseEvent, + this)); + setFocusPolicy(QWidget::WheelFocus); setFocus(); setCursor(ibeamCursor); @@ -85,7 +94,25 @@ QContentPane::QContentPane(QWorkArea * parent) // stupid moc strikes again connect(wa_->scrollbar_, SIGNAL(valueChanged(int)), this, SLOT(scrollBarChanged(int))); +} + +void QContentPane::generateSyntheticMouseEvent() +{ + // Set things off to generate the _next_ 'pseudo' event. + if (synthetic_mouse_event_.restart_timeout) + synthetic_mouse_event_.timeout.start(); + + // Has anything changed on-screen since the last timeout signal + // was received? + double const scrollbar_value = wa_->scrollbar_->value(); + if (scrollbar_value != synthetic_mouse_event_.scrollbar_value_old) { + // Yes it has. Store the params used to check this. + synthetic_mouse_event_.scrollbar_value_old = scrollbar_value; + + // ... and dispatch the event to the LyX core. + wa_->dispatch(synthetic_mouse_event_.cmd); + } } @@ -115,6 +142,9 @@ void QContentPane::mousePressEvent(QMouseEvent * e) void QContentPane::mouseReleaseEvent(QMouseEvent * e) { + if (synthetic_mouse_event_.timeout.running()) + synthetic_mouse_event_.timeout.stop(); + FuncRequest const cmd(LFUN_MOUSE_RELEASE, e->x(), e->y(), q_button_state(e->button())); wa_->dispatch(cmd); @@ -125,7 +155,53 @@ void QContentPane::mouseMoveEvent(QMouseEvent * e) { FuncRequest const cmd(LFUN_MOUSE_MOTION, e->x(), e->y(), q_motion_state(e->state())); - wa_->dispatch(cmd); + + // If we're above or below the work area... + if (e->y() <= 0 || e->y() >= height()) { + // Store the event, to be handled when the timeout expires. + synthetic_mouse_event_.cmd = cmd; + + if (synthetic_mouse_event_.timeout.running()) + // Discard the event. Note that it _may_ be handled + // when the timeout expires if + // synthetic_mouse_event_.cmd has not been overwritten. + // Ie, when the timeout expires, we handle the + // most recent event but discard all others that + // occurred after the one used to start the timeout + // in the first place. + return; + else { + synthetic_mouse_event_.restart_timeout = true; + synthetic_mouse_event_.timeout.start(); + // Fall through to handle this event... + } + + } else if (synthetic_mouse_event_.timeout.running()) { + // Store the event, to be possibly handled when the timeout + // expires. + // Once the timeout has expired, normal control is returned + // to mouseMoveEvent (restart_timeout = false). + // This results in a much smoother 'feel' when moving the + // mouse back into the work area. + synthetic_mouse_event_.cmd = cmd; + synthetic_mouse_event_.restart_timeout = false; + return; + } + + // Has anything changed on-screen since the last QMouseEvent + // was received? + double const scrollbar_value = wa_->scrollbar_->value(); + if (e->x() != synthetic_mouse_event_.x_old || + e->y() != synthetic_mouse_event_.y_old || + scrollbar_value != synthetic_mouse_event_.scrollbar_value_old) { + // Yes it has. Store the params used to check this. + synthetic_mouse_event_.x_old = e->x(); + synthetic_mouse_event_.y_old = e->y(); + synthetic_mouse_event_.scrollbar_value_old = scrollbar_value; + + // ... and dispatch the event to the LyX core. + wa_->dispatch(cmd); + } } @@ -200,4 +276,3 @@ void QContentPane::trackScrollbar(bool track_on) { track_scrollbar_ = track_on; } - diff --git a/src/frontends/qt2/QContentPane.h b/src/frontends/qt2/QContentPane.h index cc892cf985..13780457b2 100644 --- a/src/frontends/qt2/QContentPane.h +++ b/src/frontends/qt2/QContentPane.h @@ -12,6 +12,13 @@ #ifndef QCONTENTPANE_H #define QCONTENTPANE_H +#ifdef emit +#undef emit +#endif + +#include "funcrequest.h" +#include "frontends/Timeout.h" + #include #include @@ -40,6 +47,27 @@ struct double_click { }; +/** Qt only emits mouse events when the mouse is being moved, but + * we want to generate 'pseudo' mouse events when the mouse button is + * pressed and the mouse cursor is below the bottom, or above the top + * of the work area. In this way, we'll be able to continue scrolling + * (and selecting) the text. + * + * This struct stores all the parameters needed to make this happen. + */ +struct SyntheticMouseEvent +{ + SyntheticMouseEvent(); + + FuncRequest cmd; + Timeout timeout; + bool restart_timeout; + int x_old; + int y_old; + double scrollbar_value_old; +}; + + /** * Widget for actually drawing the document on */ @@ -76,6 +104,10 @@ public slots: void scrollBarChanged(int); private: + /// The slot connected to SyntheticMouseEvent::timeout. + void generateSyntheticMouseEvent(); + SyntheticMouseEvent synthetic_mouse_event_; + /// bool track_scrollbar_; /// owning widget -- 2.39.2