#include <QContextMenuEvent>
#include <QInputContext>
#include <QHelpEvent>
+#ifdef Q_WS_MAC
+#include <QMacStyle>
+#endif
#include <QMainWindow>
#include <QPainter>
#include <QPalette>
#else
int const CursorWidth = 1;
#endif
+int const TabIndicatorWidth = 3;
#undef KeyPress
#undef NoModifier
void draw(QPainter & painter)
{
- if (show_ && rect_.isValid()) {
- switch (shape_) {
- case L_SHAPE:
- painter.fillRect(rect_.x(), rect_.y(), CursorWidth, rect_.height(), color_);
- painter.setPen(color_);
- painter.drawLine(rect_.bottomLeft().x() + CursorWidth, rect_.bottomLeft().y(),
- rect_.bottomRight().x(), rect_.bottomLeft().y());
- break;
-
- case REVERSED_L_SHAPE:
- painter.fillRect(rect_.x() + rect_.height() / 3, rect_.y(), CursorWidth, rect_.height(), color_);
- painter.setPen(color_);
- painter.drawLine(rect_.bottomRight().x() - CursorWidth, rect_.bottomLeft().y(),
- rect_.bottomLeft().x(), rect_.bottomLeft().y());
- break;
-
- default:
- painter.fillRect(rect_, color_);
- break;
+ if (!show_ || !rect_.isValid())
+ return;
+
+ int y = rect_.top();
+ int l = x_ - rect_.left();
+ int r = rect_.right() - x_;
+ int bot = rect_.bottom();
+
+ // draw vertica linel
+ painter.fillRect(x_, y, CursorWidth, rect_.height(), color_);
+
+ // draw RTL/LTR indication
+ painter.setPen(color_);
+ if (l_shape_) {
+ if (rtl_)
+ painter.drawLine(x_, bot, x_ - l, bot);
+ else
+ painter.drawLine(x_, bot, x_ + CursorWidth + r, bot);
+ }
+
+ // draw completion triangle
+ if (completable_) {
+ int m = y + rect_.height() / 2;
+ int d = TabIndicatorWidth - 1;
+ if (rtl_) {
+ painter.drawLine(x_ - 1, m - d, x_ - 1 - d, m);
+ painter.drawLine(x_ - 1, m + d, x_ - 1 - d, m);
+ } else {
+ painter.drawLine(x_ + CursorWidth, m - d, x_ + CursorWidth + d, m);
+ painter.drawLine(x_ + CursorWidth, m + d, x_ + CursorWidth + d, m);
}
}
}
- void update(int x, int y, int h, CursorShape shape)
+ void update(int x, int y, int h, bool l_shape,
+ bool rtl, bool completable)
{
color_ = guiApp->colorCache().get(Color_cursor);
- shape_ = shape;
- switch (shape) {
- case L_SHAPE:
- rect_ = QRect(x, y, CursorWidth + h / 3, h);
- break;
- case REVERSED_L_SHAPE:
- rect_ = QRect(x - h / 3, y, CursorWidth + h / 3, h);
- break;
- default:
- rect_ = QRect(x, y, CursorWidth, h);
- break;
+ l_shape_ = l_shape;
+ rtl_ = rtl;
+ completable_ = completable;
+ x_ = x;
+
+ // extension to left and right
+ int l = 0;
+ int r = 0;
+
+ // RTL/LTR indication
+ if (l_shape_) {
+ if (rtl)
+ l += h / 3;
+ else
+ r += h / 3;
}
+
+ // completion triangle
+ if (completable_) {
+ if (rtl)
+ l = max(l, TabIndicatorWidth);
+ else
+ r = max(r, TabIndicatorWidth);
+ }
+
+ // compute overall rectangle
+ rect_ = QRect(x - l, y, CursorWidth + r + l, h);
}
void show(bool set_show = true) { show_ = set_show; }
QRect const & rect() { return rect_; }
private:
- ///
- CursorShape shape_;
+ /// cursor is in RTL or LTR text
+ bool rtl_;
+ /// indication for RTL or LTR
+ bool l_shape_;
+ /// triangle to show that a completion is available
+ bool completable_;
///
bool show_;
///
QColor color_;
- ///
+ /// rectangle, possibly with l_shape and completion triangle
QRect rect_;
+ /// x position (were the vertical line is drawn)
+ int x_;
};
GuiWorkArea::GuiWorkArea(Buffer & buffer, GuiView & lv)
: buffer_view_(new BufferView(buffer)), lyx_view_(&lv),
- cursor_visible_(false),
- need_resize_(false), schedule_redraw_(false),
- preedit_lines_(1)
+ cursor_visible_(false),
+ need_resize_(false), schedule_redraw_(false),
+ preedit_lines_(1), completer_(this)
{
buffer.workAreaManager().add(this);
// Setup the signals
setAcceptDrops(true);
setMouseTracking(true);
setMinimumSize(100, 70);
+#ifdef Q_WS_MACX
+ setFrameStyle(QFrame::NoFrame);
+#else
+ setFrameStyle(QFrame::Box);
+#endif
updateWindowTitle();
viewport()->setAutoFillBackground(false);
}
-
GuiWorkArea::~GuiWorkArea()
{
buffer_view_->buffer().workAreaManager().remove(this);
if (lyxrc.full_screen_scrollbar)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
} else {
+#ifdef Q_WS_MACX
+ setFrameStyle(QFrame::NoFrame);
+#else
setFrameStyle(QFrame::Box);
+#endif
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}
}
// No need to do anything if this is the current view. The BufferView
// metrics are already up to date.
- if (lyx_view_ != guiApp->currentView()) {
+ if (lyx_view_ != guiApp->currentView()
+ || lyx_view_->currentWorkArea() != this) {
// FIXME: it would be nice to optimize for the off-screen case.
buffer_view_->updateMetrics();
buffer_view_->cursor().fixIfBroken();
// Skip these when selecting
if (cmd.action != LFUN_MOUSE_MOTION) {
+ completer_.updateVisibility(false, false);
lyx_view_->updateLayoutList();
lyx_view_->updateToolbars();
}
if (cursor_visible_)
return;
- CursorShape shape = BAR_SHAPE;
-
+ // RTL or not RTL
+ bool l_shape = false;
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;
- }
+ if (!samelang || isrtl != bp.language->rightToLeft())
+ l_shape = true;
// The ERT language hack needs fixing up
if (realfont.language() == latex_language)
- shape = BAR_SHAPE;
+ l_shape = false;
Font const font = buffer_view_->cursor().getFont();
FontMetrics const & fm = theFontMetrics(font);
int h = asc + des;
int x = 0;
int y = 0;
- buffer_view_->cursor().getPos(x, y);
+ Cursor & cur = buffer_view_->cursor();
+ cur.getPos(x, y);
y -= asc;
// if it doesn't touch the screen, don't try to show it
+ bool cursorInView = true;
if (y + h < 0 || y >= viewport()->height())
- return;
-
- cursor_visible_ = true;
- showCursor(x, y, h, shape);
+ cursorInView = false;
+
+ // show cursor on screen
+ bool completable = completer_.completionAvailable()
+ && !completer_.popupVisible()
+ && !completer_.inlineVisible();
+ if (cursorInView) {
+ cursor_visible_ = true;
+ showCursor(x, y, h, l_shape, isrtl, completable);
+ }
}
}
-void GuiWorkArea::focusInEvent(QFocusEvent * /*event*/)
+void GuiWorkArea::focusInEvent(QFocusEvent * e)
{
- lyx_view_->setCurrentWorkArea(this);
+ if (lyx_view_->currentWorkArea() != this)
+ lyx_view_->setCurrentWorkArea(this);
+
// Repaint the whole screen.
// Note: this is different from redraw() as only the backing pixmap
// will be redrawn, which is cheap.
viewport()->repaint();
startBlinkingCursor();
+ QAbstractScrollArea::focusInEvent(e);
}
-void GuiWorkArea::focusOutEvent(QFocusEvent * /*event*/)
+void GuiWorkArea::focusOutEvent(QFocusEvent * e)
{
stopBlinkingCursor();
+ QAbstractScrollArea::focusOutEvent(e);
}
FuncRequest cmd(LFUN_MOUSE_TRIPLE, e->x(), e->y(),
q_button_state(e->button()));
dispatch(cmd);
+ e->accept();
return;
}
FuncRequest const cmd(LFUN_MOUSE_PRESS, e->x(), e->y(),
q_button_state(e->button()));
dispatch(cmd, q_key_state(e->modifiers()));
+ e->accept();
}
FuncRequest const cmd(LFUN_MOUSE_RELEASE, e->x(), e->y(),
q_button_state(e->button()));
dispatch(cmd);
+ e->accept();
}
FuncRequest cmd(LFUN_MOUSE_MOTION, e->x(), e->y(),
q_motion_state(e->buttons()));
+ e->accept();
+
// If we're above or below the work area...
if (e->y() <= 20 || e->y() >= viewport()->height() - 20) {
// Make sure only a synthetic event can cause a page scroll,
<< " lines = " << lines);
verticalScrollBar()->setValue(verticalScrollBar()->value() -
int(lines * verticalScrollBar()->singleStep()));
+ e->accept();
}
void GuiWorkArea::keyPressEvent(QKeyEvent * ev)
{
+ // intercept some keys if completion popup is visible
+ if (completer_.popupVisible()) {
+ switch (ev->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ completer_.activate();
+ ev->accept();
+ return;
+ }
+ }
+
+ // intercept keys for the completion
+ if (ev->key() == Qt::Key_Tab) {
+ completer_.tab();
+ ev->accept();
+ return;
+ }
+
+ if (completer_.popupVisible() && ev->key() == Qt::Key_Escape) {
+ completer_.hidePopup();
+ ev->accept();
+ return;
+ }
+
+ if (completer_.inlineVisible() && ev->key() == Qt::Key_Escape) {
+ completer_.hideInline();
+ ev->accept();
+ return;
+ }
+
// do nothing if there are other events
// (the auto repeated events come too fast)
// \todo FIXME: remove hard coded Qt keys, process the key binding
ev->x(), ev->y(),
q_button_state(ev->button()));
dispatch(cmd);
+ ev->accept();
}
{
QAbstractScrollArea::resizeEvent(ev);
need_resize_ = true;
+ ev->accept();
}
QPainter pain(viewport());
pain.drawPixmap(rc, screen_, rc);
cursor_->draw(pain);
+ ev->accept();
}
}
-void GuiWorkArea::showCursor(int x, int y, int h, CursorShape shape)
+void GuiWorkArea::showCursor(int x, int y, int h,
+ bool l_shape, bool rtl, bool completable)
{
if (schedule_redraw_) {
buffer_view_->updateMetrics();
return;
}
- cursor_->update(x, y, h, shape);
+ cursor_->update(x, y, h, l_shape, rtl, completable);
cursor_->show();
viewport()->update(cursor_->rect());
}
}
+bool GuiWorkArea::isFullScreen()
+{
+ return lyx_view_ && lyx_view_->isFullScreen();
+}
+
+
////////////////////////////////////////////////////////////////////
//
// TabWorkArea
//
////////////////////////////////////////////////////////////////////
+#ifdef Q_WS_MACX
+class NoTabFrameMacStyle : public QMacStyle {
+public:
+ ///
+ QRect subElementRect(SubElement element, const QStyleOption * option,
+ const QWidget * widget = 0 ) const
+ {
+ QRect rect = QMacStyle::subElementRect(element, option, widget);
+ bool noBar = static_cast<QTabWidget const *>(widget)->count() <= 1;
+
+ // The Qt Mac style puts the contents into a 3 pixel wide box
+ // which looks very ugly and not like other Mac applications.
+ // Hence we remove this here, and moreover the 16 pixel round
+ // frame above if the tab bar is hidden.
+ if (element == QStyle::SE_TabWidgetTabContents) {
+ rect.adjust(- rect.left(), 0, rect.left(), 0);
+ if (noBar)
+ rect.setTop(0);
+ }
+
+ return rect;
+ }
+};
+
+NoTabFrameMacStyle noTabFramemacStyle;
+#endif
+
+
TabWorkArea::TabWorkArea(QWidget * parent) : QTabWidget(parent)
{
+#ifdef Q_WS_MACX
+ setStyle(&noTabFramemacStyle);
+#endif
+
QPalette pal = palette();
pal.setColor(QPalette::Active, QPalette::Button,
pal.color(QPalette::Active, QPalette::Window));
pal.setColor(QPalette::Inactive, QPalette::Button,
pal.color(QPalette::Inactive, QPalette::Window));
+ QObject::connect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(on_currentTabChanged(int)));
+
+ QToolButton * closeBufferButton = new QToolButton(this);
+ closeBufferButton->setPalette(pal);
+ // FIXME: rename the icon to closebuffer.png
+ closeBufferButton->setIcon(QIcon(":/images/closetab.png"));
+ closeBufferButton->setText("Close File");
+ closeBufferButton->setAutoRaise(true);
+ closeBufferButton->setCursor(Qt::ArrowCursor);
+ closeBufferButton->setToolTip(qt_("Close File"));
+ closeBufferButton->setEnabled(true);
+ QObject::connect(closeBufferButton, SIGNAL(clicked()),
+ this, SLOT(closeCurrentBuffer()));
+ setCornerWidget(closeBufferButton, Qt::TopRightCorner);
+
QToolButton * closeTabButton = new QToolButton(this);
- closeTabButton->setPalette(pal);
- closeTabButton->setIcon(QIcon(":/images/closetab.png"));
- closeTabButton->setText("Close");
+ closeTabButton->setPalette(pal);
+ closeTabButton->setIcon(QIcon(":/images/hidetab.png"));
+ closeTabButton->setText("Hide tab");
closeTabButton->setAutoRaise(true);
closeTabButton->setCursor(Qt::ArrowCursor);
- closeTabButton->setToolTip(tr("Close tab"));
+ closeTabButton->setToolTip(qt_("Hide tab"));
closeTabButton->setEnabled(true);
-
- QObject::connect(this, SIGNAL(currentChanged(int)),
- this, SLOT(on_currentTabChanged(int)));
QObject::connect(closeTabButton, SIGNAL(clicked()),
this, SLOT(closeCurrentTab()));
+ setCornerWidget(closeTabButton, Qt::TopLeftCorner);
- setCornerWidget(closeTabButton);
setUsesScrollButtons(true);
}
wa->setUpdatesEnabled(false);
// Hide tabbar if there's no tab (avoid a resize and a flashing tabbar
// when hiding it again below).
- showBar(count() > 0);
+ if (!(currentWorkArea() && currentWorkArea()->isFullScreen()))
+ showBar(count() > 0);
addTab(wa, wa->windowTitle());
QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
this, SLOT(updateTabText(GuiWorkArea *)));
- // Hide tabbar if there's only one tab.
- showBar(count() > 1);
+ if (currentWorkArea() && currentWorkArea()->isFullScreen())
+ setFullScreen(true);
+ else
+ // Hide tabbar if there's only one tab.
+ showBar(count() > 1);
+
return wa;
}
if (count()) {
// make sure the next work area is enabled.
currentWidget()->setUpdatesEnabled(true);
- // Hide tabbar if there's only one tab.
- showBar(count() > 1);
+ if ((currentWorkArea() && currentWorkArea()->isFullScreen()))
+ setFullScreen(true);
+ else
+ // Hide tabbar if there's only one tab.
+ showBar(count() > 1);
}
return true;
}
}
-void TabWorkArea::closeCurrentTab()
+void TabWorkArea::closeCurrentBuffer()
{
lyx::dispatch(FuncRequest(LFUN_BUFFER_CLOSE));
}
+void TabWorkArea::closeCurrentTab()
+{
+ removeWorkArea(currentWorkArea());
+}
+
+
void TabWorkArea::updateTabText(GuiWorkArea * wa)
{
int const i = indexOf(wa);