From 34859c9a4fb66b038268b9444de85692c5fa5471 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Mon, 12 Nov 2007 22:15:51 +0000 Subject: [PATCH] make WorkArea a pure interface, move all implementation to GuiWorkArea git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21557 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/frontends/KeyModifier.h | 10 +- src/frontends/Makefile.am | 1 - src/frontends/WorkArea.cpp | 349 ------------------------------ src/frontends/WorkArea.h | 86 ++------ src/frontends/WorkAreaManager.cpp | 23 +- src/frontends/WorkAreaManager.h | 13 +- src/frontends/qt4/GuiView.cpp | 2 +- src/frontends/qt4/GuiView.h | 13 +- src/frontends/qt4/GuiWorkArea.cpp | 340 +++++++++++++++++++++++++++-- src/frontends/qt4/GuiWorkArea.h | 118 +++++++--- 10 files changed, 448 insertions(+), 507 deletions(-) delete mode 100644 src/frontends/WorkArea.cpp diff --git a/src/frontends/KeyModifier.h b/src/frontends/KeyModifier.h index db5beffd43..7c8035f91f 100644 --- a/src/frontends/KeyModifier.h +++ b/src/frontends/KeyModifier.h @@ -1,6 +1,6 @@ // -*- C++ -*- /** - * \file key_state.h + * \file KeyModifier.h * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * @@ -19,10 +19,10 @@ namespace lyx { /// modifier key states enum KeyModifier { - NoModifier = 0, //< no modifiers held + NoModifier = 0, //< no modifiers held ControlModifier = 1, //< control button held - AltModifier = 2, //< alt/meta key held - ShiftModifier = 4 //< shift key held + AltModifier = 2, //< alt/meta key held + ShiftModifier = 4 //< shift key held }; @@ -42,4 +42,4 @@ inline void operator|=(KeyModifier & s1, KeyModifier s2) } // namespace lyx -#endif // KEY_STATE_H +#endif // KEYMODIFIER_H diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am index 9cacd46995..eabbacbe08 100644 --- a/src/frontends/Makefile.am +++ b/src/frontends/Makefile.am @@ -34,7 +34,6 @@ liblyxfrontends_la_SOURCES = \ Clipboard.h \ Gui.h \ Selection.h \ - WorkArea.cpp \ WorkArea.h \ WorkAreaManager.cpp \ WorkAreaManager.h \ diff --git a/src/frontends/WorkArea.cpp b/src/frontends/WorkArea.cpp deleted file mode 100644 index 849cadeaec..0000000000 --- a/src/frontends/WorkArea.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/** - * \file WorkArea.cpp - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author John Levon - * \author Abdelrazak Younes - * - * Full author contact details are available in file CREDITS. - * - * Splash screen code added by Angus Leeming - */ - -#include - -#include "frontends/WorkArea.h" - -#include "frontends/Application.h" -#include "frontends/Dialogs.h" -#include "frontends/FontMetrics.h" -#include "frontends/LyXView.h" -#include "frontends/WorkAreaManager.h" - -#include "BufferView.h" -#include "Buffer.h" -#include "BufferParams.h" -#include "CoordCache.h" -#include "Cursor.h" -#include "debug.h" -#include "Font.h" -#include "FuncRequest.h" -#include "KeySymbol.h" -#include "Language.h" -#include "LyXFunc.h" -#include "LyXRC.h" -#include "MetricsInfo.h" - -#include "gettext.h" -#include "support/FileName.h" -#include "support/filetools.h" -#include "support/ForkedcallsController.h" - -#include -#include -#include - -using std::endl; -using std::min; -using std::max; -using std::string; - - -namespace { - -// All the below connection objects are needed because of a bug in some -// versions of GCC (<=2.96 are on the suspects list.) By having and assigning -// to these connections we avoid a segfault upon startup, and also at exit. -// (Lgb) - -boost::signals::connection timecon; - -} // anon namespace - -namespace lyx { - -using support::ForkedcallsController; -using support::makeDisplayPath; -using support::onlyFilename; - -namespace frontend { - -WorkArea::WorkArea(Buffer & buffer, LyXView & lv) - : buffer_view_(new BufferView(buffer)), lyx_view_(&lv), - cursor_visible_(false), cursor_timeout_(400) -{ - buffer.workAreaManager().add(this); - // Setup the signals - timecon = cursor_timeout_.timeout - .connect(boost::bind(&WorkArea::toggleCursor, this)); - - cursor_timeout_.start(); -} - - -WorkArea::~WorkArea() -{ - buffer_view_->buffer().workAreaManager().remove(this); - delete buffer_view_; -} - - -void WorkArea::close() -{ - lyx_view_->removeWorkArea(this); -} - -//void WorkArea::setLyXView(LyXView * lyx_view) -//{ -// lyx_view_ = lyx_view; -//} - - -BufferView & WorkArea::bufferView() -{ - return *buffer_view_; -} - - -BufferView const & WorkArea::bufferView() const -{ - return *buffer_view_; -} - - -void WorkArea::stopBlinkingCursor() -{ - cursor_timeout_.stop(); - hideCursor(); -} - - -void WorkArea::startBlinkingCursor() -{ - showCursor(); - cursor_timeout_.restart(); -} - - -void WorkArea::redraw() -{ - if (!isVisible()) - // No need to redraw in this case. - return; - - // No need to do anything if this is the current view. The BufferView - // metrics are already up to date. - if (lyx_view_ != theApp()->currentView()) { - // FIXME: it would be nice to optimize for the off-screen case. - buffer_view_->updateMetrics(); - buffer_view_->cursor().fixIfBroken(); - } - - updateScrollbar(); - - // update cursor position, because otherwise it has to wait until - // the blinking interval is over - if (cursor_visible_) { - hideCursor(); - showCursor(); - } - - ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo(); - - LYXERR(Debug::WORKAREA) << "WorkArea::redraw screen" << endl; - - int const ymin = std::max(vi.y1, 0); - int const ymax = vi.p2 < vi.size - 1 ? vi.y2 : height(); - - expose(0, ymin, width(), ymax - ymin); - - //LYXERR(Debug::WORKAREA) - //<< " ymin = " << ymin << " width() = " << width() -// << " ymax-ymin = " << ymax-ymin << std::endl; - - if (lyxerr.debugging(Debug::WORKAREA)) - buffer_view_->coordCache().dump(); -} - - -void WorkArea::processKeySym(KeySymbol const & key, KeyModifier mod) -{ - // In order to avoid bad surprise in the middle of an operation, we better stop - // the blinking cursor. - stopBlinkingCursor(); - - theLyXFunc().setLyXView(lyx_view_); - theLyXFunc().processKeySym(key, mod); -} - - -void WorkArea::dispatch(FuncRequest const & cmd0, KeyModifier mod) -{ - // Handle drag&drop - if (cmd0.action == LFUN_FILE_OPEN) { - lyx_view_->dispatch(cmd0); - return; - } - - theLyXFunc().setLyXView(lyx_view_); - - FuncRequest cmd; - - if (cmd0.action == LFUN_MOUSE_PRESS) { - if (mod == ShiftModifier) - cmd = FuncRequest(cmd0, "region-select"); - else if (mod == ControlModifier) - cmd = FuncRequest(cmd0, "paragraph-select"); - else - cmd = cmd0; - } - else - cmd = cmd0; - - // In order to avoid bad surprise in the middle of an operation, we better stop - // the blinking cursor. - if (!(cmd.action == LFUN_MOUSE_MOTION - && cmd.button() == mouse_button::none)) - stopBlinkingCursor(); - - buffer_view_->mouseEventDispatch(cmd); - - // Skip these when selecting - if (cmd.action != LFUN_MOUSE_MOTION) { - lyx_view_->updateLayoutChoice(false); - lyx_view_->updateToolbars(); - } - - // GUI tweaks except with mouse motion with no button pressed. - if (!(cmd.action == LFUN_MOUSE_MOTION - && cmd.button() == mouse_button::none)) { - // Slight hack: this is only called currently when we - // clicked somewhere, so we force through the display - // of the new status here. - lyx_view_->clearMessage(); - - // Show the cursor immediately after any operation. - startBlinkingCursor(); - } -} - - -void WorkArea::resizeBufferView() -{ - // WARNING: Please don't put any code that will trigger a repaint here! - // We are already inside a paint event. - lyx_view_->setBusy(true); - buffer_view_->resize(width(), height()); - lyx_view_->updateLayoutChoice(false); - lyx_view_->setBusy(false); -} - - -void WorkArea::updateScrollbar() -{ - buffer_view_->updateScrollbar(); - ScrollbarParameters const & scroll_ = buffer_view_->scrollbarParameters(); - setScrollbarParams(scroll_.height, scroll_.position, - scroll_.lineScrollHeight); -} - - -void WorkArea::showCursor() -{ - if (cursor_visible_) - return; - - CursorShape shape = BAR_SHAPE; - - Font const & realfont = buffer_view_->cursor().real_current_font; - BufferParams const & bp = buffer_view_->buffer().params(); - bool const samelang = realfont.language() == bp.language; - bool const isrtl = realfont.isVisibleRightToLeft(); - - if (!samelang || isrtl != bp.language->rightToLeft()) { - shape = L_SHAPE; - if (isrtl) - shape = REVERSED_L_SHAPE; - } - - // The ERT language hack needs fixing up - if (realfont.language() == latex_language) - shape = BAR_SHAPE; - - Font const font = buffer_view_->cursor().getFont(); - FontMetrics const & fm = theFontMetrics(font); - int const asc = fm.maxAscent(); - int const des = fm.maxDescent(); - int h = asc + des; - int x = 0; - int y = 0; - buffer_view_->cursor().getPos(x, y); - y -= asc; - - // if it doesn't touch the screen, don't try to show it - if (y + h < 0 || y >= height()) - return; - - cursor_visible_ = true; - showCursor(x, y, h, shape); -} - - -void WorkArea::hideCursor() -{ - if (!cursor_visible_) - return; - - cursor_visible_ = false; - removeCursor(); -} - - -void WorkArea::toggleCursor() -{ - if (cursor_visible_) - hideCursor(); - else - showCursor(); - - // Use this opportunity to deal with any child processes that - // have finished but are waiting to communicate this fact - // to the rest of LyX. - ForkedcallsController & fcc = ForkedcallsController::get(); - fcc.handleCompletedProcesses(); - - cursor_timeout_.restart(); -} - -void WorkArea::updateWindowTitle() -{ - docstring maximize_title; - docstring minimize_title; - - Buffer & buf = buffer_view_->buffer(); - string const cur_title = buf.absFileName(); - if (!cur_title.empty()) { - maximize_title = makeDisplayPath(cur_title, 30); - minimize_title = from_utf8(onlyFilename(cur_title)); - if (!buf.isClean()) { - maximize_title += _(" (changed)"); - minimize_title += char_type('*'); - } - if (buf.isReadonly()) - maximize_title += _(" (read only)"); - } - - setWindowTitle(maximize_title, minimize_title); -} - - -void WorkArea::setReadOnly(bool) -{ - updateWindowTitle(); - if (this == lyx_view_->currentWorkArea()) - lyx_view_->getDialogs().updateBufferDependent(false); -} - -} // namespace frontend -} // namespace lyx diff --git a/src/frontends/WorkArea.h b/src/frontends/WorkArea.h index 306b655532..e8508d06f0 100644 --- a/src/frontends/WorkArea.h +++ b/src/frontends/WorkArea.h @@ -15,18 +15,10 @@ #define BASE_WORKAREA_H #include "frontends/KeyModifier.h" -#include "frontends/Delegates.h" - -#include "support/Timeout.h" -#include "support/docstring.h" - -#undef CursorShape namespace lyx { -class Buffer; class BufferView; -class FuncRequest; class KeySymbol; namespace frontend { @@ -34,16 +26,6 @@ namespace frontend { class LyXView; class Painter; -/// types of cursor in work area -enum CursorShape { - /// normal I-beam - BAR_SHAPE, - /// L-shape for locked insets of a different language - L_SHAPE, - /// reverse L-shape for RTL text - REVERSED_L_SHAPE -}; - /** * The work area class represents the widget that provides the * view onto a document. It is owned by the BufferView, and @@ -55,22 +37,22 @@ class WorkArea { public: /// - WorkArea(Buffer & buffer, LyXView & lv); + WorkArea() {} virtual ~WorkArea(); /// - void setLyXView(LyXView & lv) { lyx_view_ = &lv; } + virtual void setLyXView(LyXView & lv) = 0; /// - BufferView & bufferView(); + virtual BufferView & bufferView() = 0; /// - BufferView const & bufferView() const; + virtual BufferView const & bufferView() const = 0; - /// \return true if has the keyboard input focus. + /// return true if has the keyboard input focus. virtual bool hasFocus() const = 0; - /// \return true if has this WorkArea is visible. + /// return true if has this WorkArea is visible. virtual bool isVisible() const = 0; /// return the width of the work area in pixels @@ -91,65 +73,23 @@ public: virtual void scheduleRedraw() = 0; /// redraw the screen, without using existing pixmap - virtual void redraw(); + virtual void redraw() = 0; /// - void stopBlinkingCursor(); - void startBlinkingCursor(); + virtual void stopBlinkingCursor() = 0; + virtual void startBlinkingCursor() = 0; /// Process Key pressed event. /// This needs to be public because it is accessed externally by GuiView. - void processKeySym(KeySymbol const & key, KeyModifier mod); + virtual void processKeySym(KeySymbol const & key, KeyModifier mod) = 0; /// close this work area. /// Slot for Buffer::closing signal. - void close(); - + virtual void close() = 0; /// This function is called when the buffer readonly status change. - virtual void setReadOnly(bool); + virtual void setReadOnly(bool) = 0; /// Update window titles of all users. - virtual void updateWindowTitle(); - -protected: - /// cause the display of the given area of the work area - virtual void expose(int x, int y, int w, int h) = 0; - - /// set title of window. - /** - * @param t main window title - * @param it iconified (short) title - */ - virtual void setWindowTitle(docstring const & t, docstring const & it) = 0; - - /// - void dispatch(FuncRequest const & cmd0, KeyModifier = NoModifier); - - /// - void resizeBufferView(); - /// hide the visible cursor, if it is visible - void hideCursor(); - /// show the cursor if it is not visible - void showCursor(); - /// toggle the cursor's visibility - void toggleCursor(); - /// hide the cursor - virtual void removeCursor() = 0; - /// paint the cursor and store the background - virtual void showCursor(int x, int y, int h, CursorShape shape) = 0; - /// - void updateScrollbar(); - - /// - BufferView * buffer_view_; - /// - LyXView * lyx_view_; - -private: - /// is the cursor currently displayed - bool cursor_visible_; - - /// - Timeout cursor_timeout_; + virtual void updateWindowTitle() = 0; }; } // namespace frontend diff --git a/src/frontends/WorkAreaManager.cpp b/src/frontends/WorkAreaManager.cpp index e3c8d3e2a7..b0eaaac6b1 100644 --- a/src/frontends/WorkAreaManager.cpp +++ b/src/frontends/WorkAreaManager.cpp @@ -11,16 +11,12 @@ #include -#include "WorkArea.h" - #include "WorkAreaManager.h" -using std::list; - -namespace lyx { +#include "WorkArea.h" -extern bool quitting; +namespace lyx { namespace frontend { void WorkAreaManager::add(WorkArea * wa) @@ -37,11 +33,8 @@ void WorkAreaManager::remove(WorkArea * wa) void WorkAreaManager::redrawAll() { - for (list::iterator it = work_areas_.begin(); - it != work_areas_.end(); ) { + for (iterator it = work_areas_.begin(); it != work_areas_.end(); ++it) (*it)->redraw(); - ++it; - } } @@ -55,21 +48,15 @@ void WorkAreaManager::closeAll() void WorkAreaManager::setReadOnly(bool on) { - for (list::iterator it = work_areas_.begin(); - it != work_areas_.end(); ) { + for (iterator it = work_areas_.begin(); it != work_areas_.end(); ++it) (*it)->setReadOnly(on); - ++it; - } } void WorkAreaManager::updateTitles() { - for (list::iterator it = work_areas_.begin(); - it != work_areas_.end(); ) { + for (iterator it = work_areas_.begin(); it != work_areas_.end(); ++it) (*it)->updateWindowTitle(); - ++it; - } } } // namespace frontend diff --git a/src/frontends/WorkAreaManager.h b/src/frontends/WorkAreaManager.h index 00f7de53fe..7d389c6703 100644 --- a/src/frontends/WorkAreaManager.h +++ b/src/frontends/WorkAreaManager.h @@ -28,27 +28,24 @@ class WorkArea; class WorkAreaManager { public: + /// WorkAreaManager() {} - /// void add(WorkArea * wa); - /// void remove(WorkArea * wa); - /// void redrawAll(); - /// void closeAll(); - /// This function is called when the buffer readonly status change. - virtual void setReadOnly(bool); - + void setReadOnly(bool); /// Update window titles of all users. - virtual void updateTitles(); + void updateTitles(); private: + typedef std::list::iterator iterator; + /// std::list work_areas_; }; diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index c79fc1a319..9fed4ddbc2 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -121,7 +121,7 @@ private: QPixmap * splash_; }; -}; +} // namespace anon struct GuiView::GuiViewPrivate diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h index 78a7859a24..b5b4466858 100644 --- a/src/frontends/qt4/GuiView.h +++ b/src/frontends/qt4/GuiView.h @@ -140,14 +140,20 @@ private: /// in order to catch Tab key press. bool event(QEvent * e); bool focusNextPrevChild(bool); + /// + QRect updateFloatingGeometry(); + +private: + /// + struct GuiViewPrivate; + GuiViewPrivate & d; + /// QTimer statusbar_timer_; /// are we quitting by the menu? bool quitting_by_menu_; - /// - QRect updateFloatingGeometry(); /// QRect floatingGeometry_; @@ -161,9 +167,6 @@ private: }; ToolbarSize toolbarSize_; - - struct GuiViewPrivate; - GuiViewPrivate& d; }; diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index e6deea60bd..06e1d824cf 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -13,25 +13,38 @@ #include "GuiWorkArea.h" -#include "GuiApplication.h" -#include "GuiPainter.h" -#include "GuiKeySymbol.h" -#include "qt_helpers.h" - -#include "frontends/LyXView.h" - #include "Buffer.h" +#include "BufferParams.h" #include "BufferView.h" +#include "CoordCache.h" #include "Cursor.h" #include "debug.h" +#include "Font.h" #include "FuncRequest.h" +#include "gettext.h" +#include "GuiApplication.h" +#include "GuiKeySymbol.h" +#include "GuiPainter.h" +#include "KeySymbol.h" +#include "Language.h" #include "LyXFunc.h" #include "LyXRC.h" +#include "MetricsInfo.h" +#include "qt_helpers.h" #include "version.h" #include "graphics/GraphicsImage.h" #include "graphics/GraphicsLoader.h" +#include "support/FileName.h" +#include "support/ForkedcallsController.h" + +#include "frontends/Application.h" +#include "frontends/Dialogs.h" // only used in setReadOnly +#include "frontends/FontMetrics.h" +#include "frontends/LyXView.h" +#include "frontends/WorkAreaManager.h" + #include #include #include @@ -42,8 +55,8 @@ #include #include -#include #include +#include #ifdef Q_WS_X11 #include @@ -60,11 +73,15 @@ int const CursorWidth = 1; #undef NoModifier using std::endl; +using std::min; +using std::max; using std::string; namespace lyx { using support::FileName; +using support::ForkedcallsController; + /// return the LyX mouse button state from Qt's static mouse_button::state q_button_state(Qt::MouseButton button) @@ -174,10 +191,31 @@ SyntheticMouseEvent::SyntheticMouseEvent() {} -GuiWorkArea::GuiWorkArea(Buffer & buf, LyXView & lv) - : WorkArea(buf, lv), need_resize_(false), schedule_redraw_(false), - preedit_lines_(1) + +// All the below connection objects are needed because of a bug in some +// versions of GCC (<=2.96 are on the suspects list.) By having and assigning +// to these connections we avoid a segfault upon startup, and also at exit. +// (Lgb) + +static boost::signals::connection timecon; + +// HACK: FIXME +WorkArea::~WorkArea() {} + + +GuiWorkArea::GuiWorkArea(Buffer & buffer, LyXView & lv) + : buffer_view_(new BufferView(buffer)), lyx_view_(&lv), + cursor_visible_(false), cursor_timeout_(400), + need_resize_(false), schedule_redraw_(false), + preedit_lines_(1) { + buffer.workAreaManager().add(this); + // Setup the signals + timecon = cursor_timeout_.timeout + .connect(boost::bind(&GuiWorkArea::toggleCursor, this)); + + cursor_timeout_.start(); + screen_ = QPixmap(viewport()->width(), viewport()->height()); cursor_ = new frontend::CursorWidget(); cursor_->hide(); @@ -200,7 +238,7 @@ GuiWorkArea::GuiWorkArea(Buffer & buf, LyXView & lv) synthetic_mouse_event_.timeout.timeout.connect( boost::bind(&GuiWorkArea::generateSyntheticMouseEvent, - this)); + this)); // Initialize the vertical Scroll Bar QObject::connect(verticalScrollBar(), SIGNAL(actionTriggered(int)), @@ -225,6 +263,237 @@ GuiWorkArea::GuiWorkArea(Buffer & buf, LyXView & lv) } + +GuiWorkArea::~GuiWorkArea() +{ + buffer_view_->buffer().workAreaManager().remove(this); + delete buffer_view_; +} + + +void GuiWorkArea::close() +{ + lyx_view_->removeWorkArea(this); +} + + +BufferView & GuiWorkArea::bufferView() +{ + return *buffer_view_; +} + + +BufferView const & GuiWorkArea::bufferView() const +{ + return *buffer_view_; +} + + +void GuiWorkArea::stopBlinkingCursor() +{ + cursor_timeout_.stop(); + hideCursor(); +} + + +void GuiWorkArea::startBlinkingCursor() +{ + showCursor(); + cursor_timeout_.restart(); +} + + +void GuiWorkArea::redraw() +{ + if (!isVisible()) + // No need to redraw in this case. + return; + + // No need to do anything if this is the current view. The BufferView + // metrics are already up to date. + if (lyx_view_ != theApp()->currentView()) { + // FIXME: it would be nice to optimize for the off-screen case. + buffer_view_->updateMetrics(); + buffer_view_->cursor().fixIfBroken(); + } + + updateScrollbar(); + + // update cursor position, because otherwise it has to wait until + // the blinking interval is over + if (cursor_visible_) { + hideCursor(); + showCursor(); + } + + ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo(); + + LYXERR(Debug::WORKAREA) << "WorkArea::redraw screen" << endl; + + int const ymin = std::max(vi.y1, 0); + int const ymax = vi.p2 < vi.size - 1 ? vi.y2 : height(); + + expose(0, ymin, width(), ymax - ymin); + + //LYXERR(Debug::WORKAREA) + //<< " ymin = " << ymin << " width() = " << width() +// << " ymax-ymin = " << ymax-ymin << std::endl; + + if (lyxerr.debugging(Debug::WORKAREA)) + buffer_view_->coordCache().dump(); +} + + +void GuiWorkArea::processKeySym(KeySymbol const & key, KeyModifier mod) +{ + // In order to avoid bad surprise in the middle of an operation, + // we better stop the blinking cursor. + stopBlinkingCursor(); + + theLyXFunc().setLyXView(lyx_view_); + theLyXFunc().processKeySym(key, mod); +} + + +void GuiWorkArea::dispatch(FuncRequest const & cmd0, KeyModifier mod) +{ + // Handle drag&drop + if (cmd0.action == LFUN_FILE_OPEN) { + lyx_view_->dispatch(cmd0); + return; + } + + theLyXFunc().setLyXView(lyx_view_); + + FuncRequest cmd; + + if (cmd0.action == LFUN_MOUSE_PRESS) { + if (mod == ShiftModifier) + cmd = FuncRequest(cmd0, "region-select"); + else if (mod == ControlModifier) + cmd = FuncRequest(cmd0, "paragraph-select"); + else + cmd = cmd0; + } + else + cmd = cmd0; + + // In order to avoid bad surprise in the middle of an operation, we better stop + // the blinking cursor. + if (!(cmd.action == LFUN_MOUSE_MOTION + && cmd.button() == mouse_button::none)) + stopBlinkingCursor(); + + buffer_view_->mouseEventDispatch(cmd); + + // Skip these when selecting + if (cmd.action != LFUN_MOUSE_MOTION) { + lyx_view_->updateLayoutChoice(false); + lyx_view_->updateToolbars(); + } + + // GUI tweaks except with mouse motion with no button pressed. + if (!(cmd.action == LFUN_MOUSE_MOTION + && cmd.button() == mouse_button::none)) { + // Slight hack: this is only called currently when we + // clicked somewhere, so we force through the display + // of the new status here. + lyx_view_->clearMessage(); + + // Show the cursor immediately after any operation. + startBlinkingCursor(); + } +} + + +void GuiWorkArea::resizeBufferView() +{ + // WARNING: Please don't put any code that will trigger a repaint here! + // We are already inside a paint event. + lyx_view_->setBusy(true); + buffer_view_->resize(width(), height()); + lyx_view_->updateLayoutChoice(false); + lyx_view_->setBusy(false); +} + + +void GuiWorkArea::updateScrollbar() +{ + buffer_view_->updateScrollbar(); + ScrollbarParameters const & scroll_ = buffer_view_->scrollbarParameters(); + setScrollbarParams(scroll_.height, scroll_.position, + scroll_.lineScrollHeight); +} + + +void GuiWorkArea::showCursor() +{ + if (cursor_visible_) + return; + + CursorShape shape = BAR_SHAPE; + + Font const & realfont = buffer_view_->cursor().real_current_font; + BufferParams const & bp = buffer_view_->buffer().params(); + bool const samelang = realfont.language() == bp.language; + bool const isrtl = realfont.isVisibleRightToLeft(); + + if (!samelang || isrtl != bp.language->rightToLeft()) { + shape = L_SHAPE; + if (isrtl) + shape = REVERSED_L_SHAPE; + } + + // The ERT language hack needs fixing up + if (realfont.language() == latex_language) + shape = BAR_SHAPE; + + Font const font = buffer_view_->cursor().getFont(); + FontMetrics const & fm = theFontMetrics(font); + int const asc = fm.maxAscent(); + int const des = fm.maxDescent(); + int h = asc + des; + int x = 0; + int y = 0; + buffer_view_->cursor().getPos(x, y); + y -= asc; + + // if it doesn't touch the screen, don't try to show it + if (y + h < 0 || y >= height()) + return; + + cursor_visible_ = true; + showCursor(x, y, h, shape); +} + + +void GuiWorkArea::hideCursor() +{ + if (!cursor_visible_) + return; + + cursor_visible_ = false; + removeCursor(); +} + + +void GuiWorkArea::toggleCursor() +{ + if (cursor_visible_) + hideCursor(); + else + showCursor(); + + // Use this opportunity to deal with any child processes that + // have finished but are waiting to communicate this fact + // to the rest of LyX. + ForkedcallsController & fcc = ForkedcallsController::get(); + fcc.handleCompletedProcesses(); + + cursor_timeout_.restart(); +} + + void GuiWorkArea::setScrollbarParams(int h, int scroll_pos, int scroll_line_step) { if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOn) @@ -441,7 +710,7 @@ void GuiWorkArea::doubleClickTimeout() void GuiWorkArea::mouseDoubleClickEvent(QMouseEvent * ev) { - dc_event_ = double_click(ev); + dc_event_ = DoubleClick(ev); QTimer::singleShot(QApplication::doubleClickInterval(), this, SLOT(doubleClickTimeout())); FuncRequest cmd(LFUN_MOUSE_DOUBLE, @@ -479,8 +748,8 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) screen_ = QPixmap(viewport()->width(), viewport()->height()); resizeBufferView(); updateScreen(); - WorkArea::hideCursor(); - WorkArea::showCursor(); + hideCursor(); + showCursor(); need_resize_ = false; } @@ -704,18 +973,51 @@ QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const } +void GuiWorkArea::updateWindowTitle() +{ + docstring maximize_title; + docstring minimize_title; + + Buffer & buf = buffer_view_->buffer(); + FileName const fileName = buf.fileName(); + if (!fileName.empty()) { + maximize_title = fileName.displayName(30); + minimize_title = from_utf8(fileName.onlyFileName()); + if (!buf.isClean()) { + maximize_title += _(" (changed)"); + minimize_title += char_type('*'); + } + if (buf.isReadonly()) + maximize_title += _(" (read only)"); + } + + setWindowTitle(maximize_title, minimize_title); +} + + +void GuiWorkArea::setReadOnly(bool) +{ + updateWindowTitle(); + if (this == lyx_view_->currentWorkArea()) + lyx_view_->getDialogs().updateBufferDependent(false); +} + + //////////////////////////////////////////////////////////////////// // // TabWorkArea // //////////////////////////////////////////////////////////////////// -TabWorkArea::TabWorkArea(QWidget * parent): QTabWidget(parent) +TabWorkArea::TabWorkArea(QWidget * parent) : QTabWidget(parent) { QPalette pal = palette(); - pal.setColor(QPalette::Active, QPalette::Button, pal.color(QPalette::Active, QPalette::Window)); - pal.setColor(QPalette::Disabled, QPalette::Button, pal.color(QPalette::Disabled, QPalette::Window)); - pal.setColor(QPalette::Inactive, QPalette::Button, pal.color(QPalette::Inactive, QPalette::Window)); + pal.setColor(QPalette::Active, QPalette::Button, + pal.color(QPalette::Active, QPalette::Window)); + pal.setColor(QPalette::Disabled, QPalette::Button, + pal.color(QPalette::Disabled, QPalette::Window)); + pal.setColor(QPalette::Inactive, QPalette::Button, + pal.color(QPalette::Inactive, QPalette::Window)); QToolButton * closeTabButton = new QToolButton(this); closeTabButton->setPalette(pal); diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index ae1f752601..54d033b43c 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -39,23 +39,38 @@ class QPaintEvent; #endif namespace lyx { + +class Buffer; + namespace frontend { +class LyXView; + +/// types of cursor in work area +enum CursorShape { + /// normal I-beam + BAR_SHAPE, + /// L-shape for locked insets of a different language + L_SHAPE, + /// reverse L-shape for RTL text + REVERSED_L_SHAPE +}; + /// for emulating triple click -class double_click { +class DoubleClick { public: + /// + DoubleClick() : state(Qt::NoButton), active(false) {} + /// + DoubleClick(QMouseEvent * e) : state(e->button()), active(true) {} + /// + bool operator==(QMouseEvent const & e) { return state == e.button(); } + /// +public: + /// Qt::MouseButton state; + /// bool active; - - bool operator==(QMouseEvent const & e) { - return state == e.button(); - } - - double_click() - : state(Qt::NoButton), active(false) {} - - double_click(QMouseEvent * e) - : state(e->button()), active(true) {} }; /** Qt only emits mouse events when the mouse is being moved, but @@ -79,11 +94,12 @@ public: double scrollbar_value_old; }; + /** - * Qt-specific implementation of the work area - * (buffer view GUI) + * Implementation of the work area (buffer view GUI) */ - class CursorWidget; +class CursorWidget; + class GuiWorkArea : public QAbstractScrollArea, public WorkArea { Q_OBJECT @@ -91,6 +107,8 @@ class GuiWorkArea : public QAbstractScrollArea, public WorkArea public: /// GuiWorkArea(Buffer & buffer, LyXView & lv); + /// + ~GuiWorkArea(); /// bool hasFocus() const { return QAbstractScrollArea::hasFocus(); } @@ -116,7 +134,36 @@ public: /// hide the cursor virtual void removeCursor(); + /// + void setLyXView(LyXView & lv) { lyx_view_ = &lv; } + /// + BufferView & bufferView(); + /// + BufferView const & bufferView() const; + /// + void redraw(); + /// + void stopBlinkingCursor(); + /// + void startBlinkingCursor(); + /// + void processKeySym(KeySymbol const & key, KeyModifier mod); +public Q_SLOTS: + /// Adjust the LyX buffer view with the position of the scrollbar. + /** + * The action argument is not used in the the code, it is there + * only for the connection to the vertical srollbar signal which + * emits an 'int' action. + */ + void adjustViewWithScrollBar(int action = 0); + /// timer to limit triple clicks + void doubleClickTimeout(); + + /// close this work area. + /// Slot for Buffer::closing signal. + void close(); + //// void setWindowTitle(docstring const & t, docstring const & it); Q_SIGNALS: @@ -124,6 +171,11 @@ Q_SIGNALS: void titleChanged(GuiWorkArea *); private: + /// This function is called when the buffer readonly status change. + void setReadOnly(bool); + + /// Update window titles of all users. + void updateWindowTitle(); /// void focusInEvent(QFocusEvent *); /// @@ -149,25 +201,34 @@ private: /// IM query QVariant inputMethodQuery(Qt::InputMethodQuery query) const; -public Q_SLOTS: - /// Adjust the LyX buffer view with the position of the scrollbar. - /** - * The action argument is not used in the the code, it is there - * only for the connection to the vertical srollbar signal which - * emits an 'int' action. - */ - void adjustViewWithScrollBar(int action = 0); - /// timer to limit triple clicks - void doubleClickTimeout(); - -private: /// The slot connected to SyntheticMouseEvent::timeout. void generateSyntheticMouseEvent(); + /// + void dispatch(FuncRequest const & cmd0, KeyModifier = NoModifier); + /// + void resizeBufferView(); + /// hide the visible cursor, if it is visible + void hideCursor(); + /// show the cursor if it is not visible + void showCursor(); + /// toggle the cursor's visibility + void toggleCursor(); + /// + void updateScrollbar(); + /// + BufferView * buffer_view_; + /// + LyXView * lyx_view_; + /// is the cursor currently displayed + bool cursor_visible_; + + /// + Timeout cursor_timeout_; /// SyntheticMouseEvent synthetic_mouse_event_; /// - double_click dc_event_; + DoubleClick dc_event_; /// CursorWidget * cursor_; @@ -181,7 +242,8 @@ private: bool schedule_redraw_; /// int preedit_lines_; -}; //GuiWorkArea +}; // GuiWorkArea + /// A tabbed set of GuiWorkAreas. class TabWorkArea : public QTabWidget -- 2.39.2