Smooth, controllable scrolling in the Qt frontend.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8178 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Angus Leeming 2003-12-02 10:10:15 +00:00
parent 35f1ab544b
commit 8a3f21cd29
3 changed files with 123 additions and 5 deletions

View 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.

View 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;
}

View File

@ -12,6 +12,13 @@
#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