#include <config.h>
+#include <boost/current_function.hpp>
+
#include "QWorkArea.h"
#include "QLPainter.h"
#include "QLyXKeySym.h"
#include "lcolorcache.h"
#include "qt_helpers.h"
-
+#include "BufferView.h"
#include "debug.h"
#include "funcrequest.h"
#include "LColor.h"
#include <boost/bind.hpp>
+///////////////////////////////////////////////////////////////
+// Specific stuff
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif
#ifdef Q_WS_MACX
#include <Carbon/Carbon.h>
-#endif
-
-#ifdef Q_OS_MAC
#include <support/lstrings.h>
-
using lyx::support::subst;
#endif
+
+// You can find other qt-immodule, X11 and MACX specific stuff
+// at the end of this file...
+///////////////////////////////////////////////////////////////
+
using std::endl;
using std::string;
namespace os = lyx::support::os;
namespace {
-QWorkArea const * wa_ptr = 0;
+
+QWorkArea * wa_ptr = 0;
/// return the LyX key state from Qt's
key_modifier::state q_key_state(Qt::ButtonState state)
{}
-
-Painter & QWorkArea::getPainter() { return painter_; }
-
-// QLPainter & QWorkArea::getQLPainter() { return painter_; }
-
-/// get the content pane widget
-QWidget * QWorkArea::getContent() const { return viewport(); }
-
-QWorkArea::QWorkArea(LyXView &, int w, int h)
- : WorkArea(), QAbstractScrollArea(qApp->mainWidget()), painter_(this)
+QWorkArea::QWorkArea(LyXView & owner, int w, int h)
+ : QAbstractScrollArea(qApp->mainWidget()), WorkArea(), view_(owner), painter_(this)
{
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setMinimumSize(100, 70);
-// setBackgroundRole(lcolorcache.get(LColor::background));
-// viewport()->setBackgroundRole(QPalette::Window);
viewport()->setAutoFillBackground(false);
viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
viewport()->setFocusPolicy(Qt::WheelFocus);
viewport()->setFocus();
-// viewport()->grabKeyboard();
setFocusPolicy(Qt::WheelFocus);
- setFocusProxy(viewport());
+
viewport()->setCursor(Qt::IBeamCursor);
resize(w, h);
show();
-
- scrolled_with_mouse_=false;
- scrolled_with_keyboard_ = false;
+ workWidth_ = w;
+ workHeight_ = h;
synthetic_mouse_event_.timeout.timeout.connect(
boost::bind(&QWorkArea::generateSyntheticMouseEvent,
this));
+
+ // Initialize the vertical Scroll Bar
+ QObject::connect(verticalScrollBar(), SIGNAL(actionTriggered(int)),
+ this, SLOT(adjustViewWithScrollBar(int)));
+
+ // PageStep only depends on the viewport height.
+ verticalScrollBar()->setPageStep(workHeight_);
+
+ lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
+ << "\n Area width\t" << width()
+ << "\n Area height\t" << height()
+ << "\n viewport width\t" << viewport()->width()
+ << "\n viewport height\t" << viewport()->height()
+ << endl;
+
/*
+ // This is the keyboard buffering stuff...
+ // I don't see any need for this under windows. The keyboard is reactive
+ // enough...
+
if ( !QObject::connect(&step_timer_, SIGNAL(timeout()),
this, SLOT(keyeventTimeout())) )
lyxerr[Debug::GUI] << "ERROR: keyeventTimeout cannot connect!" << endl;
+
+ // Start the timer, one-shot.
+ step_timer_.start(50, true);
*/
- if ( !QObject::connect(verticalScrollBar(), SIGNAL(actionTriggered(int)),
- this, SLOT(adjustViewWithScrollBar(int))) )
- lyxerr[Debug::GUI] << "ERROR: adjustViewWithScrollBar cannot connect!" << endl;
-
+ ///////////////////////////////////////////////////////////////////////
+ // Specific stuff goes here...
+
#if USE_INPUT_METHODS
// to make qt-immodule work
setInputMethodEnabled(true);
#endif
+
#ifdef Q_WS_X11
// doubleClickInterval() is 400 ms on X11 witch is just too long.
// On Windows and Mac OS X, the operating system's value is used.
QApplication::setDoubleClickInterval(300);
#endif
- // Start the timer, one-shot.
- step_timer_.start(50, true);
-
- //viewport()->resize(w, h);
- pixmap_.reset(new QPixmap(viewport()->width(), viewport()->height()));
-
- this->workAreaResize();
-
- lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
- << "\n Area width\t" << width()
- << "\n Area height\t" << height()
- << "\n viewport width\t" << viewport()->width()
- << "\n viewport height\t" << viewport()->height()
- << endl;
-
-// this->QWidget::resize(w,h);
-
#ifdef Q_WS_MACX
wa_ptr = this;
#endif
void QWorkArea::setScrollbarParams(int h, int scroll_pos, int scroll_line_step)
{
- /*
- if (scrolled_with_mouse_)
- {
- scrolled_with_mouse_=false;
- return;
- }
- */
-
- //if (scroll_pos_ == scroll_pos)
- //{
- // verticalScrollBar()->triggerAction(QAbstractSlider::SliderMove);
- int scroll_pos_ = scroll_pos;
- //}
- int scroll_line_step_ = scroll_line_step;
- int scroll_page_step_ = viewport()->height();
-
// do what cursor movement does (some grey)
h += height() / 4;
int scroll_max_ = std::max(0, h - height());
- //scrolled_with_keyboard_=true;
-
verticalScrollBar()->setRange(0, scroll_max_);
- verticalScrollBar()->setSliderPosition(scroll_pos_);
- verticalScrollBar()->setLineStep(scroll_line_step_);
- verticalScrollBar()->setPageStep(scroll_page_step_);
+ verticalScrollBar()->setSliderPosition(scroll_pos);
+ verticalScrollBar()->setLineStep(scroll_line_step);
}
void QWorkArea::adjustViewWithScrollBar(int action)
<< " linestep=" << verticalScrollBar()->lineStep()
<< endl;
- this->scrollDocView(verticalScrollBar()->sliderPosition());
-
-// scrolled_with_mouse_ = true;
-}
-
-#ifdef Q_WS_X11
-bool lyxX11EventFilter(XEvent * xev)
-{
- switch (xev->type) {
- case SelectionRequest:
- lyxerr[Debug::GUI] << "X requested selection." << endl;
- if (wa_ptr)
- wa_ptr->selectionRequested();
- break;
- case SelectionClear:
- lyxerr[Debug::GUI] << "Lost selection." << endl;
- if (wa_ptr)
- wa_ptr->selectionLost();
- break;
- }
- return false;
-}
-#endif
-
-#ifdef Q_WS_MACX
-namespace{
-OSErr checkAppleEventForMissingParams(const AppleEvent& theAppleEvent)
- {
- DescType returnedType;
- Size actualSize;
- OSErr err = AEGetAttributePtr(&theAppleEvent, keyMissedKeywordAttr,
- typeWildCard, &returnedType, nil, 0,
- &actualSize);
- switch (err) {
- case errAEDescNotFound:
- return noErr;
- case noErr:
- return errAEEventNotHandled;
- default:
- return err;
- }
- }
+ view_.view()->scrollDocView(verticalScrollBar()->sliderPosition());
}
-pascal OSErr handleOpenDocuments(const AppleEvent* inEvent,
- AppleEvent* /*reply*/, long /*refCon*/)
-{
- QString s_arg;
- AEDescList documentList;
- OSErr err = AEGetParamDesc(inEvent, keyDirectObject, typeAEList,
- &documentList);
- if (err != noErr)
- return err;
-
- err = checkAppleEventForMissingParams(*inEvent);
- if (err == noErr) {
- long documentCount;
- err = AECountItems(&documentList, &documentCount);
- for (long documentIndex = 1;
- err == noErr && documentIndex <= documentCount;
- documentIndex++) {
- DescType returnedType;
- Size actualSize;
- AEKeyword keyword;
- FSRef ref;
- char qstr_buf[1024];
- err = AESizeOfNthItem(&documentList, documentIndex,
- &returnedType, &actualSize);
- if (err == noErr) {
- err = AEGetNthPtr(&documentList, documentIndex,
- typeFSRef, &keyword,
- &returnedType, (Ptr)&ref,
- sizeof(FSRef), &actualSize);
- if (err == noErr) {
- FSRefMakePath(&ref, (UInt8*)qstr_buf,
- 1024);
- s_arg=QString::fromUtf8(qstr_buf);
- wa_ptr->dispatch(
- FuncRequest(LFUN_FILE_OPEN,
- fromqstr(s_arg)));
- break;
- }
- }
- } // for ...
- }
- AEDisposeDesc(&documentList);
- return err;
-}
-#endif // Q_WS_MACX
void QWorkArea::haveSelection(bool own) const
{
- wa_ptr = this;
+ /// \todo ask X11 and MAC devels why this wa_ptr is useful.
+ wa_ptr = const_cast<QWorkArea*>(this);
if (!QApplication::clipboard()->supportsSelection())
return;
lyxerr[Debug::ACTION] << "getClipboard: " << (const char*) str << endl;
if (str.isNull())
return string();
-#ifdef Q_OS_MAC
+#ifdef Q_WS_MACX
// The MAC clipboard uses \r for lineendings, and we use \n
return subst(fromqstr(str), '\r', '\n');
#else
void QWorkArea::putClipboard(string const & str) const
{
-#ifdef Q_OS_MAC
+#ifdef Q_WS_MACX
// The MAC clipboard uses \r for lineendings, and we use \n
QApplication::clipboard()->setText(toqstr(subst(str, '\n', '\r')),
- QClipboard::Selection);
+ QClipboard::Selection);
#else
QApplication::clipboard()->setText(toqstr(str), QClipboard::Selection);
#endif
/// \todo Ask lyx-devel is this is enough:
/// if (event->mimeData()->hasFormat("text/plain"))
- /// event->acceptProposedAction();
+ /// event->acceptProposedAction();
}
for (QStringList::Iterator i = files.begin();
i!=files.end(); ++i) {
string const file = os::internal_path(fromqstr(*i));
- dispatch(FuncRequest(LFUN_FILE_OPEN, file));
+ view_.view()->workAreaDispatch(FuncRequest(LFUN_FILE_OPEN, file));
}
}
}
-/*
-void QWorkArea::scrollContentsBy(int dx, int dy)
-{
- lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
- << " scroll by dx=" << dx
- << " dy=" << dy
- << " verticalScrollBar val=" << verticalScrollBar()->value()
- << " min=" << verticalScrollBar()->minimum()
- << " max=" << verticalScrollBar()->maximum()
- << " pagestep=" << verticalScrollBar()->pageStep()
- << " linestep=" << verticalScrollBar()->lineStep()
- << endl;
-
- if (scrolled_with_keyboard_)
- {
- scrolled_with_keyboard_=false;
- return;
- }
-
- this->scrollDocView(verticalScrollBar()->value());
- scrolled_with_mouse_ = true;
-}
-*/
-#if USE_INPUT_METHODS
-// to make qt-immodule work
-
-void QWorkArea::inputMethodEvent(QInputMethodEvent * e)
-{
- QString const text = e->text();
- if (!text.isEmpty()) {
- int key = 0;
- // needed to make math superscript work on some systems
- // ideally, such special coding should not be necessary
- if (text == "^")
- key = Qt::Key_AsciiCircum;
- QKeyEvent ev(QEvent::KeyPress, key, *text.ascii(), 0, text);
- keyPressEvent(&ev);
- }
- e->accept();
-}
-#endif
void QWorkArea::mousePressEvent(QMouseEvent * e)
{
FuncRequest cmd(LFUN_MOUSE_TRIPLE,
dc_event_.x, dc_event_.y,
q_button_state(dc_event_.state));
- this->dispatch(cmd);
+ view_.view()->workAreaDispatch(cmd);
return;
}
FuncRequest const cmd(LFUN_MOUSE_PRESS, e->x(), e->y(),
q_button_state(e->button()));
- this->dispatch(cmd);
+ view_.view()->workAreaDispatch(cmd);
}
FuncRequest const cmd(LFUN_MOUSE_RELEASE, e->x(), e->y(),
q_button_state(e->button()));
- this->dispatch(cmd);
+ view_.view()->workAreaDispatch(cmd);
}
q_motion_state(e->state()));
// If we're above or below the work area...
- if (e->y() <= 20 || e->y() >= viewport()->QWidget::height() - 20) {
+ if (e->y() <= 20 || e->y() >= viewport()->height() - 20) {
// Make sure only a synthetic event can cause a page scroll,
// so they come at a steady rate:
if (e->y() <= 20)
// _Force_ a scroll up:
cmd.y = -40;
else
- cmd.y = viewport()->QWidget::height();
+ cmd.y = viewport()->height();
// Store the event, to be handled when the timeout expires.
synthetic_mouse_event_.cmd = cmd;
synthetic_mouse_event_.scrollbar_value_old = scrollbar_value;
// ... and dispatch the event to the LyX core.
- this->dispatch(cmd);
+ view_.view()->workAreaDispatch(cmd);
}
}
void QWorkArea::wheelEvent(QWheelEvent * e)
{
-// verticalScrollBar()->setValue(verticalScrollBar()->value() - e->delta());
+ // Wheel rotation by one notch results in a delta() of 120 (see
+ // documentation of QWheelEvent)
+ int const lines = QApplication::wheelScrollLines() * e->delta() / 120;
+ verticalScrollBar()->setValue(verticalScrollBar()->value() -
+ lines * verticalScrollBar()->lineStep());
+ adjustViewWithScrollBar();
}
-void QWorkArea::keyPressEvent(QKeyEvent * e)
-{
- lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
- << " count=" << e->count()
- << " text=" << (const char *) e->text()
- << " isAutoRepeat=" << e->isAutoRepeat()
- << " key=" << e->key()
- << endl;
-
- //viewport()->grabKeyboard();
-// keyeventQueue_.push(boost::shared_ptr<QKeyEvent>(new QKeyEvent(*e)));
-
- boost::shared_ptr<QLyXKeySym> sym(new QLyXKeySym);
- sym->set(e);
- this->workAreaKeyPress(sym, q_key_state(e->state()));
-
-}
-
void QWorkArea::generateSyntheticMouseEvent()
{
// Set things off to generate the _next_ 'pseudo' event.
synthetic_mouse_event_.scrollbar_value_old = scrollbar_value;
// ... and dispatch the event to the LyX core.
- this->dispatch(synthetic_mouse_event_.cmd);
+ view_.view()->workAreaDispatch(synthetic_mouse_event_.cmd);
}
}
+void QWorkArea::keyPressEvent(QKeyEvent * e)
+{
+ lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
+ << " count=" << e->count()
+ << " text=" << (const char *) e->text()
+ << " isAutoRepeat=" << e->isAutoRepeat()
+ << " key=" << e->key()
+ << endl;
+
+// keyeventQueue_.push(boost::shared_ptr<QKeyEvent>(new QKeyEvent(*e)));
+
+ boost::shared_ptr<QLyXKeySym> sym(new QLyXKeySym);
+ sym->set(e);
+ view_.view()->workAreaKeyPress(sym, q_key_state(e->state()));
+}
+
+// This is not used for now...
void QWorkArea::keyeventTimeout()
{
bool handle_autos = true;
continue;
}
- boost::shared_ptr<QLyXKeySym> sym(new QLyXKeySym);
+ boost::shared_ptr<QLyXKeySym> sym(new QLyXKeySym);
sym->set(ev.get());
- lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
- << " count=" << ev->count()
- << " text=" << (const char *) ev->text()
- << " isAutoRepeat=" << ev->isAutoRepeat()
- << " key=" << ev->key()
- << endl;
+ lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
+ << " count=" << ev->count()
+ << " text=" << (const char *) ev->text()
+ << " isAutoRepeat=" << ev->isAutoRepeat()
+ << " key=" << ev->key()
+ << endl;
- this->workAreaKeyPress(sym, q_key_state(ev->state()));
+ view_.view()->workAreaKeyPress(sym, q_key_state(ev->state()));
keyeventQueue_.pop();
handle_autos = false;
FuncRequest cmd(LFUN_MOUSE_DOUBLE,
dc_event_.x, dc_event_.y,
q_button_state(dc_event_.state));
- this->dispatch(cmd);
+ view_.view()->workAreaDispatch(cmd);
}
void QWorkArea::resizeEvent(QResizeEvent * resizeEvent)
{
- pixmap_.reset(new QPixmap(viewport()->width(), viewport()->height()));
+ workWidth_ = viewport()->width();
+ workHeight_ = viewport()->height();
+
+ verticalScrollBar()->setPageStep(viewport()->height());
- scrolled_with_mouse_=false;
- scrolled_with_keyboard_=false;
+ screen_device_ = QPixmap(viewport()->width(), viewport()->height());
+ paint_device_ = QImage(viewport()->width(), viewport()->height(), QImage::Format_RGB32);
- this->workAreaResize();
+ view_.view()->workAreaResize();
+ /*
lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
- << "\n QWidget width\t" << viewport()->width()
- << "\n QWidget height\t" << viewport()->height()
+ << "\n QWidget width\t" << this->QWidget::width()
+ << "\n QWidget height\t" << this->QWidget::height()
+ << "\n viewport width\t" << viewport()->width()
+ << "\n viewport height\t" << viewport()->height()
<< "\n QResizeEvent rect left\t" << rect().left()
<< "\n QResizeEvent rect right\t" << rect().right()
<< endl;
+ */
+}
+
+void QWorkArea::update(int x, int y, int w, int h)
+{
+ //screen_device_.fromImage(paint_device_);
+ QPainter q(&screen_device_);
+ q.drawImage(x, y, paint_device_.copy(x, y, w, h));
+
+ viewport()->update(x, y, w, h);
}
void QWorkArea::paintEvent(QPaintEvent * e)
{
-/*
+ /*
lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
- << "\n QWidget width\t" << viewport()->width()
- << "\n QWidget height\t" << viewport()->height()
+ << "\n QWidget width\t" << this->width()
+ << "\n QWidget height\t" << this->height()
+ << "\n viewport width\t" << viewport()->width()
+ << "\n viewport height\t" << viewport()->height()
+ << "\n pixmap width\t" << pixmap_->width()
+ << "\n pixmap height\t" << pixmap_->height()
<< "\n QPaintEvent x\t" << e->rect().x()
- << "\n QPaintEvent y\t" << e->rect().x()
+ << "\n QPaintEvent y\t" << e->rect().y()
<< "\n QPaintEvent w\t" << e->rect().width()
<< "\n QPaintEvent h\t" << e->rect().height()
<< endl;
-*/
+ */
QPainter q(viewport());
- q.drawPixmap(e->rect(), *pixmap_.get(), e->rect());
+ q.drawPixmap(e->rect(), screen_device_, e->rect());
+}
+
+
+QPixmap QWorkArea::copyScreen(int x, int y, int w, int h) const
+{
+ return screen_device_.copy(x, y, w, h);
+}
+
+void QWorkArea::drawScreen(int x, int y, QPixmap pixmap)
+{
+ QPainter q(&screen_device_);
+ q.drawPixmap(x, y, pixmap);
+ viewport()->update(x, y, pixmap.width(), pixmap.height());
+}
+
+
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+// Specific stuff
+
+////////////////////////////////////////////////////////////////////////
+// qt-immodule specific stuff goes here...
+
+#if USE_INPUT_METHODS
+// to make qt-immodule work
+
+void QWorkArea::inputMethodEvent(QInputMethodEvent * e)
+{
+ QString const text = e->text();
+ if (!text.isEmpty()) {
+ int key = 0;
+ // needed to make math superscript work on some systems
+ // ideally, such special coding should not be necessary
+ if (text == "^")
+ key = Qt::Key_AsciiCircum;
+ QKeyEvent ev(QEvent::KeyPress, key, *text.ascii(), 0, text);
+ keyPressEvent(&ev);
+ }
+ e->accept();
+}
+#endif
+
+
+////////////////////////////////////////////////////////////////////////
+// X11 specific stuff goes here...
+
+#ifdef Q_WS_X11
+bool lyxX11EventFilter(XEvent * xev)
+{
+ switch (xev->type) {
+ case SelectionRequest:
+ lyxerr[Debug::GUI] << "X requested selection." << endl;
+ if (wa_ptr)
+ wa_ptr->view().view()->selectionRequested();
+ break;
+ case SelectionClear:
+ lyxerr[Debug::GUI] << "Lost selection." << endl;
+ if (wa_ptr)
+ wa_ptr->view().view()->selectionLost();
+ break;
+ }
+ return false;
+}
+#endif
-// q.drawPixmap(QPoint(r.x(), r.y()),
-// *pixmap_.get(), r);
+
+////////////////////////////////////////////////////////////////////////
+// Mac OSX specific stuff goes here...
+
+#ifdef Q_WS_MACX
+namespace{
+OSErr checkAppleEventForMissingParams(const AppleEvent& theAppleEvent)
+ {
+ DescType returnedType;
+ Size actualSize;
+ OSErr err = AEGetAttributePtr(&theAppleEvent, keyMissedKeywordAttr,
+ typeWildCard, &returnedType, nil, 0,
+ &actualSize);
+ switch (err) {
+ case errAEDescNotFound:
+ return noErr;
+ case noErr:
+ return errAEEventNotHandled;
+ default:
+ return err;
+ }
+ }
}
+
+pascal OSErr handleOpenDocuments(const AppleEvent* inEvent,
+ AppleEvent* /*reply*/, long /*refCon*/)
+{
+ QString s_arg;
+ AEDescList documentList;
+ OSErr err = AEGetParamDesc(inEvent, keyDirectObject, typeAEList,
+ &documentList);
+ if (err != noErr)
+ return err;
+
+ err = checkAppleEventForMissingParams(*inEvent);
+ if (err == noErr) {
+ long documentCount;
+ err = AECountItems(&documentList, &documentCount);
+ for (long documentIndex = 1;
+ err == noErr && documentIndex <= documentCount;
+ documentIndex++) {
+ DescType returnedType;
+ Size actualSize;
+ AEKeyword keyword;
+ FSRef ref;
+ char qstr_buf[1024];
+ err = AESizeOfNthItem(&documentList, documentIndex,
+ &returnedType, &actualSize);
+ if (err == noErr) {
+ err = AEGetNthPtr(&documentList, documentIndex,
+ typeFSRef, &keyword,
+ &returnedType, (Ptr)&ref,
+ sizeof(FSRef), &actualSize);
+ if (err == noErr) {
+ FSRefMakePath(&ref, (UInt8*)qstr_buf,
+ 1024);
+ s_arg=QString::fromUtf8(qstr_buf);
+ wa_ptr->view().view()->workAreaDispatch(
+ FuncRequest(LFUN_FILE_OPEN,
+ fromqstr(s_arg)));
+ break;
+ }
+ }
+ } // for ...
+ }
+ AEDisposeDesc(&documentList);
+ return err;
+}
+#endif // Q_WS_MACX