#include "GuiApplication.h"
#include "GuiKeySymbol.h"
#include "GuiPainter.h"
-#include "GuiPopupMenu.h"
#include "GuiView.h"
#include "KeySymbol.h"
#include "Language.h"
#include "LyXRC.h"
#include "MetricsInfo.h"
#include "qt_helpers.h"
+#include "Text.h"
#include "version.h"
#include "graphics/GraphicsImage.h"
#include <QContextMenuEvent>
#include <QInputContext>
#include <QHelpEvent>
-#ifdef Q_WS_MAC
+#ifdef Q_WS_MACX
#include <QMacStyle>
#endif
#include <QMainWindow>
+#include <QMenu>
#include <QPainter>
#include <QPalette>
+#include <QPixmapCache>
#include <QScrollBar>
-#include <QTabBar>
#include <QTimer>
#include <QToolButton>
#include <QToolTip>
if (time > 0) {
cursor_timeout_.setInterval(time);
cursor_timeout_.start();
- } else
+ } else {
// let's initialize this just to be safe
cursor_timeout_.setInterval(500);
+ }
screen_ = QPixmap(viewport()->width(), viewport()->height());
cursor_ = new frontend::CursorWidget();
cursor_->hide();
+ // HACK: Prevents an additional redraw when the scrollbar pops up
+ // which regularily happens on documents with more than one page.
+ // The policy should be set to "Qt::ScrollBarAsNeeded" soon.
+ // Since we have no geometry information yet, we assume that
+ // a document needs a scrollbar if there is more then four
+ // paragraph in the outermost text.
+ if (buffer.text().paragraphs().size() > 4)
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ QTimer::singleShot(50, this, SLOT(fixVerticalScrollBar()));
+
+
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setAcceptDrops(true);
setMouseTracking(true);
}
+void GuiWorkArea::fixVerticalScrollBar()
+{
+ if (!isFullScreen())
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+}
+
+
void GuiWorkArea::close()
{
lyx_view_->removeWorkArea(this);
theLyXFunc().setLyXView(lyx_view_);
theLyXFunc().processKeySym(key, mod);
-
}
cursorInView = false;
// show cursor on screen
- bool completable = completer_.completionAvailable()
+ bool completable = cur.inset().showCompletionCursor()
+ && completer_.completionAvailable()
&& !completer_.popupVisible()
&& !completer_.inlineVisible();
if (cursorInView) {
{
ScrollbarParameters const & scroll_ = buffer_view_->scrollbarParameters();
+ // Block the scrollbar signal to prevent recursive signal/slot calling.
+ verticalScrollBar()->blockSignals(true);
verticalScrollBar()->setRange(scroll_.min, scroll_.max);
verticalScrollBar()->setPageStep(scroll_.page_step);
verticalScrollBar()->setSingleStep(scroll_.single_step);
- // Block the scrollbar signal to prevent recursive signal/slot calling.
- verticalScrollBar()->blockSignals(true);
verticalScrollBar()->setValue(scroll_.position);
verticalScrollBar()->setSliderPosition(scroll_.position);
verticalScrollBar()->blockSignals(false);
QAbstractScrollArea::contextMenuEvent(e);
return;
}
- QMenu * menu = guiApp->menus().menu(toqstr(name));
+ QMenu * menu = guiApp->menus().menu(toqstr(name), *lyx_view_);
if (!menu) {
QAbstractScrollArea::contextMenuEvent(e);
return;
}
-void GuiWorkArea::wheelEvent(QWheelEvent * e)
+void GuiWorkArea::wheelEvent(QWheelEvent * ev)
{
// Wheel rotation by one notch results in a delta() of 120 (see
// documentation of QWheelEvent)
- double const lines = qApp->wheelScrollLines()
- * lyxrc.mouse_wheel_speed
- * e->delta() / 120.0;
- LYXERR(Debug::SCROLLING, "wheelScrollLines = " << qApp->wheelScrollLines()
- << " delta = " << e->delta()
- << " lines = " << lines);
- verticalScrollBar()->setValue(verticalScrollBar()->value() -
- int(lines * verticalScrollBar()->singleStep()));
- e->accept();
+ int delta = ev->delta() / 120;
+ if (ev->modifiers() & Qt::ControlModifier) {
+ lyxrc.zoom -= 5 * delta;
+ if (lyxrc.zoom < 10)
+ lyxrc.zoom = 10;
+ // The global QPixmapCache is used in GuiPainter to cache text
+ // painting so we must reset it.
+ QPixmapCache::clear();
+ guiApp->fontLoader().update();
+ lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
+ } else {
+ double const lines = qApp->wheelScrollLines()
+ * lyxrc.mouse_wheel_speed * delta;
+ LYXERR(Debug::SCROLLING, "wheelScrollLines = " << qApp->wheelScrollLines()
+ << " delta = " << ev->delta() << " lines = " << lines);
+ verticalScrollBar()->setValue(verticalScrollBar()->value() -
+ int(lines * verticalScrollBar()->singleStep()));
+ }
+ ev->accept();
}
public:
///
QRect subElementRect(SubElement element, const QStyleOption * option,
- const QWidget * widget = 0 ) const
+ const QWidget * widget = 0) const
{
QRect rect = QMacStyle::subElementRect(element, option, widget);
bool noBar = static_cast<QTabWidget const *>(widget)->count() <= 1;
}
};
-NoTabFrameMacStyle noTabFramemacStyle;
+NoTabFrameMacStyle noTabFrameMacStyle;
#endif
-TabWorkArea::TabWorkArea(QWidget * parent) : QTabWidget(parent)
+TabWorkArea::TabWorkArea(QWidget * parent)
+ : QTabWidget(parent), clicked_tab_(-1)
{
#ifdef Q_WS_MACX
- setStyle(&noTabFramemacStyle);
+ setStyle(&noTabFrameMacStyle);
#endif
QPalette pal = palette();
QObject::connect(closeBufferButton, SIGNAL(clicked()),
this, SLOT(closeCurrentBuffer()));
setCornerWidget(closeBufferButton, Qt::TopRightCorner);
-
- QToolButton * closeTabButton = new QToolButton(this);
- closeTabButton->setPalette(pal);
- closeTabButton->setIcon(QIcon(":/images/hidetab.png"));
- closeTabButton->setText("Hide tab");
- closeTabButton->setAutoRaise(true);
- closeTabButton->setCursor(Qt::ArrowCursor);
- closeTabButton->setToolTip(qt_("Hide tab"));
- closeTabButton->setEnabled(true);
- QObject::connect(closeTabButton, SIGNAL(clicked()),
- this, SLOT(closeCurrentTab()));
- setCornerWidget(closeTabButton, Qt::TopLeftCorner);
-
+
+ // setup drag'n'drop
+ QTabBar* tb = new DragTabBar;
+ connect(tb, SIGNAL(tabMoveRequested(int, int)),
+ this, SLOT(moveTab(int, int)));
+ setTabBar(tb);
+
+ // make us responsible for the context menu of the tabbar
+ tb->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tb, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(showContextMenu(const QPoint &)));
+
setUsesScrollButtons(true);
}
return 0;
GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(currentWidget());
- BOOST_ASSERT(wa);
+ LASSERT(wa, /**/);
return wa;
}
{
for (int i = 0; i != count(); ++i) {
GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(widget(i));
- BOOST_ASSERT(wa);
+ LASSERT(wa, return 0);
if (&wa->bufferView().buffer() == &buffer)
return wa;
}
{
while (count()) {
GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(widget(0));
- BOOST_ASSERT(wa);
+ LASSERT(wa, /**/);
removeTab(0);
delete wa;
}
bool TabWorkArea::setCurrentWorkArea(GuiWorkArea * work_area)
{
- BOOST_ASSERT(work_area);
+ LASSERT(work_area, /**/);
int index = indexOf(work_area);
if (index == -1)
return false;
bool TabWorkArea::removeWorkArea(GuiWorkArea * work_area)
{
- BOOST_ASSERT(work_area);
+ LASSERT(work_area, return false);
int index = indexOf(work_area);
if (index == -1)
return false;
if (count()) {
// make sure the next work area is enabled.
currentWidget()->setUpdatesEnabled(true);
- if ((currentWorkArea() && currentWorkArea()->isFullScreen()))
+ if (currentWorkArea() && currentWorkArea()->isFullScreen())
setFullScreen(true);
else
// Hide tabbar if there's only one tab.
showBar(count() > 1);
+ } else {
+ lastWorkAreaRemoved();
}
+
return true;
}
void TabWorkArea::on_currentTabChanged(int i)
{
+ // returns e.g. on application destruction
+ if (i == -1)
+ return;
GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(widget(i));
- BOOST_ASSERT(wa);
+ LASSERT(wa, return);
BufferView & bv = wa->bufferView();
bv.cursor().fixIfBroken();
bv.updateMetrics();
void TabWorkArea::closeCurrentBuffer()
{
+ if (clicked_tab_ != -1)
+ setCurrentIndex(clicked_tab_);
+
lyx::dispatch(FuncRequest(LFUN_BUFFER_CLOSE));
}
void TabWorkArea::closeCurrentTab()
{
- removeWorkArea(currentWorkArea());
+ if (clicked_tab_ == -1)
+ removeWorkArea(currentWorkArea());
+ else {
+ GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(widget(clicked_tab_));
+ LASSERT(wa, /**/);
+ removeWorkArea(wa);
+ }
}
setTabText(i, wa->windowTitle());
}
+
+void TabWorkArea::showContextMenu(const QPoint & pos)
+{
+ // which tab?
+ clicked_tab_ = static_cast<DragTabBar *>(tabBar())->tabAt(pos);
+ if (clicked_tab_ != -1) {
+ // show tab popup
+ QMenu popup;
+ popup.addAction(QIcon(":/images/hidetab.png"),
+ qt_("Hide tab"), this, SLOT(closeCurrentTab()));
+ popup.addAction(QIcon(":/images/closetab.png"),
+ qt_("Close tab"), this, SLOT(closeCurrentBuffer()));
+ popup.exec(tabBar()->mapToGlobal(pos));
+
+ clicked_tab_ = -1;
+ }
+}
+
+
+void TabWorkArea::moveTab(int fromIndex, int toIndex)
+{
+ QWidget * w = widget(fromIndex);
+ QIcon icon = tabIcon(fromIndex);
+ QString text = tabText(fromIndex);
+
+ setCurrentIndex(fromIndex);
+ removeTab(fromIndex);
+ insertTab(toIndex, w, icon, text);
+ setCurrentIndex(toIndex);
+}
+
+
+DragTabBar::DragTabBar(QWidget* parent)
+ : QTabBar(parent)
+{
+ setAcceptDrops(true);
+}
+
+
+#if QT_VERSION < 0x040300
+int DragTabBar::tabAt(QPoint const & position) const
+{
+ const int max = count();
+ for (int i = 0; i < max; ++i) {
+ if (tabRect(i).contains(position))
+ return i;
+ }
+ return -1;
+}
+#endif
+
+
+void DragTabBar::mousePressEvent(QMouseEvent * event)
+{
+ if (event->button() == Qt::LeftButton)
+ dragStartPos_ = event->pos();
+ QTabBar::mousePressEvent(event);
+}
+
+
+void DragTabBar::mouseMoveEvent(QMouseEvent * event)
+{
+ // If the left button isn't pressed anymore then return
+ if (!(event->buttons() & Qt::LeftButton))
+ return;
+
+ // If the distance is too small then return
+ if ((event->pos() - dragStartPos_).manhattanLength()
+ < QApplication::startDragDistance())
+ return;
+
+ // did we hit something after all?
+ int tab = tabAt(dragStartPos_);
+ if (tab == -1)
+ return;
+
+ // simulate button release to remove highlight from button
+ int i = currentIndex();
+ QMouseEvent me(QEvent::MouseButtonRelease, dragStartPos_,
+ event->button(), event->buttons(), 0);
+ QTabBar::mouseReleaseEvent(&me);
+ setCurrentIndex(i);
+
+ // initiate Drag
+ QDrag * drag = new QDrag(this);
+ QMimeData * mimeData = new QMimeData;
+ // a crude way to distinguish tab-reodering drops from other ones
+ mimeData->setData("action", "tab-reordering") ;
+ drag->setMimeData(mimeData);
+
+#if QT_VERSION >= 0x040300
+ // get tab pixmap as cursor
+ QRect r = tabRect(tab);
+ QPixmap pixmap(r.size());
+ render(&pixmap, - r.topLeft());
+ drag->setPixmap(pixmap);
+ drag->exec();
+#else
+ drag->start(Qt::MoveAction);
+#endif
+
+}
+
+
+void DragTabBar::dragEnterEvent(QDragEnterEvent * event)
+{
+ // Only accept if it's an tab-reordering request
+ QMimeData const * m = event->mimeData();
+ QStringList formats = m->formats();
+ if (formats.contains("action")
+ && m->data("action") == "tab-reordering")
+ event->acceptProposedAction();
+}
+
+
+void DragTabBar::dropEvent(QDropEvent * event)
+{
+ int fromIndex = tabAt(dragStartPos_);
+ int toIndex = tabAt(event->pos());
+
+ // Tell interested objects that
+ if (fromIndex != toIndex)
+ tabMoveRequested(fromIndex, toIndex);
+ event->acceptProposedAction();
+}
+
+
} // namespace frontend
} // namespace lyx