#include <config.h>
+#include <boost/bind.hpp>
+
#include "QWorkArea.h"
#include "QContentPane.h"
#include "QLyXKeySym.h"
#include <qtimer.h>
#include <qapplication.h>
-#include "funcrequest.h"
-
-
namespace {
/// return the LyX key state from Qt's
} // 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);
// 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);
+ }
}
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);
{
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);
+ }
}
{
track_scrollbar_ = track_on;
}
-
#ifndef QCONTENTPANE_H
#define QCONTENTPANE_H
+#ifdef emit
+#undef emit
+#endif
+
+#include "funcrequest.h"
+#include "frontends/Timeout.h"
+
#include <qwidget.h>
#include <qpixmap.h>
};
+/** 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
*/
void scrollBarChanged(int);
private:
+ /// The slot connected to SyntheticMouseEvent::timeout.
+ void generateSyntheticMouseEvent();
+ SyntheticMouseEvent synthetic_mouse_event_;
+
///
bool track_scrollbar_;
/// owning widget