]> git.lyx.org Git - features.git/commitdiff
Smooth, controllable scrolling in the Qt frontend.
authorAngus Leeming <leeming@lyx.org>
Tue, 2 Dec 2003 10:10:15 +0000 (10:10 +0000)
committerAngus Leeming <leeming@lyx.org>
Tue, 2 Dec 2003 10:10:15 +0000 (10:10 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8178 a592a061-630c-0410-9148-cb99ea01b6c8

src/frontends/qt2/ChangeLog
src/frontends/qt2/QContentPane.C
src/frontends/qt2/QContentPane.h

index 1cbb50a83845e971e129c885d2e054982d2f0f1e..dd7e0ddc29015f4bb0bf2b3c3dc039cc9e896b32 100644 (file)
@@ -1,3 +1,14 @@
+2003-12-01  Angus Leeming  <leeming@lyx.org>
+
+       * 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  <j.spitzmueller@gmx.de>
 
        * QVSpace.C: remove VSPACE::NONE, remove restore button.
index 43ac1e011c6c6eb72e89848d93e1e834589352d1..c169dedab35ef65af71c1306c8088e37c91f676c 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <config.h>
 
+#include <boost/bind.hpp>
+
 #include "QWorkArea.h"
 #include "QContentPane.h"
 #include "QLyXKeySym.h"
@@ -18,9 +20,6 @@
 #include <qtimer.h>
 #include <qapplication.h>
 
-#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;
 }
-
index cc892cf98567684f943348052178726608245fdc..13780457b21b137dd84e3f4e66c827f90fa019ce 100644 (file)
 #ifndef QCONTENTPANE_H
 #define QCONTENTPANE_H
 
+#ifdef emit
+#undef emit
+#endif
+
+#include "funcrequest.h"
+#include "frontends/Timeout.h"
+
 #include <qwidget.h>
 #include <qpixmap.h>
 
@@ -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