3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 // Qt defines a macro 'signals' that clashes with a boost namespace.
14 // All is well if the namespace is visible first.
15 #include "QWorkArea.h"
17 #include "QContentPane.h"
18 #include "QLyXKeySym.h"
20 #include <qapplication.h>
24 #include <boost/bind.hpp>
28 /// return the LyX key state from Qt's
29 key_modifier::state q_key_state(Qt::ButtonState state)
31 key_modifier::state k = key_modifier::none;
32 if (state & Qt::ControlButton)
33 k |= key_modifier::ctrl;
34 if (state & Qt::ShiftButton)
35 k |= key_modifier::shift;
36 if (state & Qt::AltButton)
37 k |= key_modifier::alt;
42 /// return the LyX mouse button state from Qt's
43 mouse_button::state q_button_state(Qt::ButtonState button)
45 mouse_button::state b = mouse_button::none;
48 b = mouse_button::button1;
51 b = mouse_button::button2;
54 b = mouse_button::button3;
63 /// return the LyX mouse button state from Qt's
64 mouse_button::state q_motion_state(Qt::ButtonState state)
66 mouse_button::state b = mouse_button::none;
67 if (state & Qt::LeftButton)
68 b |= mouse_button::button1;
69 if (state & Qt::MidButton)
70 b |= mouse_button::button2;
71 if (state & Qt::RightButton)
72 b |= mouse_button::button3;
79 SyntheticMouseEvent::SyntheticMouseEvent()
80 : timeout(200), restart_timeout(true),
81 x_old(-1), y_old(-1), scrollbar_value_old(-1.0)
85 QContentPane::QContentPane(QWorkArea * parent)
86 : QWidget(parent, "content_pane", WRepaintNoErase),
87 track_scrollbar_(true), wa_(parent)
89 synthetic_mouse_event_.timeout.timeout.connect(
90 boost::bind(&QContentPane::generateSyntheticMouseEvent,
93 setFocusPolicy(QWidget::WheelFocus);
95 setCursor(ibeamCursor);
96 #if QT_VERSION >= 0x030200
97 // to make qt-immodule work
98 setInputMethodEnabled(true);
101 // stupid moc strikes again
102 connect(wa_->scrollbar_, SIGNAL(valueChanged(int)),
103 this, SLOT(scrollBarChanged(int)));
107 #if QT_VERSION >= 0x030200
108 // to make qt-immodule work
109 void QContentPane::imStartEvent(QIMEvent *e)
115 void QContentPane::imComposeEvent(QIMEvent *e)
121 void QContentPane::imEndEvent(QIMEvent *e)
123 QString const text = e->text();
124 if (!text.isEmpty()) {
126 // needed to make math superscript work on some systems
127 // ideally, such special coding should not be necessary
129 key = Qt::Key_AsciiCircum;
130 QKeyEvent ev(QEvent::KeyPress, key, *text.ascii(), 0, text);
138 void QContentPane::generateSyntheticMouseEvent()
140 // Set things off to generate the _next_ 'pseudo' event.
141 if (synthetic_mouse_event_.restart_timeout)
142 synthetic_mouse_event_.timeout.start();
144 // Has anything changed on-screen since the last timeout signal
146 double const scrollbar_value = wa_->scrollbar_->value();
147 if (scrollbar_value != synthetic_mouse_event_.scrollbar_value_old) {
148 // Yes it has. Store the params used to check this.
149 synthetic_mouse_event_.scrollbar_value_old = scrollbar_value;
151 // ... and dispatch the event to the LyX core.
152 wa_->dispatch(synthetic_mouse_event_.cmd);
157 void QContentPane::scrollBarChanged(int val)
159 if (track_scrollbar_)
160 wa_->scrollDocView(val);
164 void QContentPane::mousePressEvent(QMouseEvent * e)
166 if (dc_event_.active && dc_event_ == *e) {
167 dc_event_.active = false;
168 FuncRequest cmd(LFUN_MOUSE_TRIPLE,
169 dc_event_.x, dc_event_.y,
170 q_button_state(dc_event_.state));
175 FuncRequest const cmd(LFUN_MOUSE_PRESS, e->x(), e->y(),
176 q_button_state(e->button()));
181 void QContentPane::mouseReleaseEvent(QMouseEvent * e)
183 if (synthetic_mouse_event_.timeout.running())
184 synthetic_mouse_event_.timeout.stop();
186 FuncRequest const cmd(LFUN_MOUSE_RELEASE, e->x(), e->y(),
187 q_button_state(e->button()));
192 void QContentPane::mouseMoveEvent(QMouseEvent * e)
194 FuncRequest const cmd(LFUN_MOUSE_MOTION, e->x(), e->y(),
195 q_motion_state(e->state()));
197 // If we're above or below the work area...
198 if (e->y() <= 0 || e->y() >= height()) {
199 // Store the event, to be handled when the timeout expires.
200 synthetic_mouse_event_.cmd = cmd;
202 if (synthetic_mouse_event_.timeout.running())
203 // Discard the event. Note that it _may_ be handled
204 // when the timeout expires if
205 // synthetic_mouse_event_.cmd has not been overwritten.
206 // Ie, when the timeout expires, we handle the
207 // most recent event but discard all others that
208 // occurred after the one used to start the timeout
209 // in the first place.
212 synthetic_mouse_event_.restart_timeout = true;
213 synthetic_mouse_event_.timeout.start();
214 // Fall through to handle this event...
217 } else if (synthetic_mouse_event_.timeout.running()) {
218 // Store the event, to be possibly handled when the timeout
220 // Once the timeout has expired, normal control is returned
221 // to mouseMoveEvent (restart_timeout = false).
222 // This results in a much smoother 'feel' when moving the
223 // mouse back into the work area.
224 synthetic_mouse_event_.cmd = cmd;
225 synthetic_mouse_event_.restart_timeout = false;
229 // Has anything changed on-screen since the last QMouseEvent
231 double const scrollbar_value = wa_->scrollbar_->value();
232 if (e->x() != synthetic_mouse_event_.x_old ||
233 e->y() != synthetic_mouse_event_.y_old ||
234 scrollbar_value != synthetic_mouse_event_.scrollbar_value_old) {
235 // Yes it has. Store the params used to check this.
236 synthetic_mouse_event_.x_old = e->x();
237 synthetic_mouse_event_.y_old = e->y();
238 synthetic_mouse_event_.scrollbar_value_old = scrollbar_value;
240 // ... and dispatch the event to the LyX core.
246 void QContentPane::wheelEvent(QWheelEvent * e)
248 wa_->scrollbar_->setValue(wa_->scrollbar_->value() - e->delta());
252 void QContentPane::keyPressEvent(QKeyEvent * e)
254 boost::shared_ptr<QLyXKeySym> sym(new QLyXKeySym);
256 wa_->workAreaKeyPress(sym, q_key_state(e->state()));
260 void QContentPane::doubleClickTimeout()
262 if (!dc_event_.active)
265 dc_event_.active = false;
267 FuncRequest cmd(LFUN_MOUSE_DOUBLE,
268 dc_event_.x, dc_event_.y,
269 q_button_state(dc_event_.state));
274 void QContentPane::mouseDoubleClickEvent(QMouseEvent * e)
276 dc_event_ = double_click(e);
278 // doubleClickInterval() is just too long.
279 QTimer::singleShot(int(QApplication::doubleClickInterval() / 1.5),
280 this, SLOT(doubleClickTimeout()));
284 void QContentPane::resizeEvent(QResizeEvent *)
286 if (!pixmap_.get()) {
287 pixmap_.reset(new QPixmap(width(), height()));
290 pixmap_->resize(width(), height());
291 wa_->workAreaResize();
295 void QContentPane::paintEvent(QPaintEvent * e)
297 if (!pixmap_.get()) {
298 pixmap_.reset(new QPixmap(width(), height()));
299 wa_->workAreaResize();
306 q.drawPixmap(QPoint(r.x(), r.y()),
311 void QContentPane::trackScrollbar(bool track_on)
313 track_scrollbar_ = track_on;