mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-26 19:25:39 +00:00
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
This commit is contained in:
parent
963470c60e
commit
34859c9a4f
@ -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
|
||||
|
@ -34,7 +34,6 @@ liblyxfrontends_la_SOURCES = \
|
||||
Clipboard.h \
|
||||
Gui.h \
|
||||
Selection.h \
|
||||
WorkArea.cpp \
|
||||
WorkArea.h \
|
||||
WorkAreaManager.cpp \
|
||||
WorkAreaManager.h \
|
||||
|
@ -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 <config.h>
|
||||
|
||||
#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 <boost/noncopyable.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
|
||||
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
|
@ -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
|
||||
|
@ -11,16 +11,12 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "WorkArea.h"
|
||||
|
||||
#include "WorkAreaManager.h"
|
||||
|
||||
using std::list;
|
||||
#include "WorkArea.h"
|
||||
|
||||
|
||||
namespace lyx {
|
||||
|
||||
extern bool quitting;
|
||||
|
||||
namespace frontend {
|
||||
|
||||
void WorkAreaManager::add(WorkArea * wa)
|
||||
@ -37,11 +33,8 @@ void WorkAreaManager::remove(WorkArea * wa)
|
||||
|
||||
void WorkAreaManager::redrawAll()
|
||||
{
|
||||
for (list<WorkArea *>::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<WorkArea *>::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<WorkArea *>::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
|
||||
|
@ -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<WorkArea *>::iterator iterator;
|
||||
///
|
||||
std::list<WorkArea *> work_areas_;
|
||||
};
|
||||
|
||||
|
@ -121,7 +121,7 @@ private:
|
||||
QPixmap * splash_;
|
||||
};
|
||||
|
||||
};
|
||||
} // namespace anon
|
||||
|
||||
|
||||
struct GuiView::GuiViewPrivate
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 <QInputContext>
|
||||
#include <QLayout>
|
||||
#include <QMainWindow>
|
||||
@ -42,8 +55,8 @@
|
||||
#include <QTabBar>
|
||||
#include <QTimer>
|
||||
|
||||
#include <boost/current_function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <QX11Info>
|
||||
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user