Terminal: Add mouse support

Change-Id: Ibeb8e13b5f8f75f16ec86f64536235587c844ffc
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-07-25 09:16:48 +02:00
parent 75d9dc2d31
commit 79e839b29f
17 changed files with 211 additions and 112 deletions

View File

@@ -1,7 +1,7 @@
add_qtc_plugin(Terminal
PLUGIN_DEPENDS Core ProjectExplorer
DEPENDS libvterm
DEPENDS libvterm ptyqt
SOURCES
celliterator.cpp celliterator.h
glyphcache.cpp glyphcache.h

View File

@@ -54,9 +54,6 @@ TerminalPane::TerminalPane(QObject *parent)
initActions();
m_lockKeyboardButton = new QToolButton();
m_lockKeyboardButton->setDefaultAction(&lockKeyboard);
m_newTerminalButton = new QToolButton();
m_newTerminalButton->setDefaultAction(&newTerminal);
@@ -94,11 +91,34 @@ TerminalPane::TerminalPane(QObject *parent)
connect(m_escSettingButton, &QToolButton::toggled, this, [this, updateEscButton] {
settings().sendEscapeToTerminal.setValue(m_escSettingButton->isChecked());
settings().writeSettings();
updateEscButton();
});
connect(&settings(), &TerminalSettings::applied, this, updateEscButton);
const auto updateLockButton = [this] {
m_lockKeyboardButton->setChecked(settings().lockKeyboard());
if (settings().lockKeyboard()) {
m_lockKeyboardButton->setIcon(LOCK_KEYBOARD_ICON.icon());
m_lockKeyboardButton->setToolTip(
Tr::tr("Qt Creator shortcuts are blocked when focus is inside the terminal."));
} else {
m_lockKeyboardButton->setIcon(UNLOCK_KEYBOARD_ICON.icon());
m_lockKeyboardButton->setToolTip(Tr::tr("Qt Creator shortcuts take precedence."));
}
};
m_lockKeyboardButton = new QToolButton();
m_lockKeyboardButton->setCheckable(true);
updateLockButton();
connect(m_lockKeyboardButton, &QToolButton::toggled, this, [this, updateLockButton] {
settings().lockKeyboard.setValue(m_lockKeyboardButton->isChecked());
updateLockButton();
});
connect(&settings(), &TerminalSettings::applied, this, updateLockButton);
}
TerminalPane::~TerminalPane() {}
@@ -249,23 +269,6 @@ void TerminalPane::initActions()
{
createShellMenu();
lockKeyboard.setCheckable(true);
lockKeyboard.setChecked(settings().lockKeyboard());
auto updateLockKeyboard = [this](bool locked) {
settings().lockKeyboard.setValue(locked);
if (locked) {
lockKeyboard.setIcon(LOCK_KEYBOARD_ICON.icon());
lockKeyboard.setToolTip(Tr::tr("Sends keyboard shortcuts to Terminal."));
} else {
lockKeyboard.setIcon(UNLOCK_KEYBOARD_ICON.icon());
lockKeyboard.setToolTip(Tr::tr("Sends keyboard shortcuts to Qt Creator."));
}
};
updateLockKeyboard(settings().lockKeyboard());
connect(&lockKeyboard, &QAction::toggled, this, updateLockKeyboard);
newTerminal.setText(Tr::tr("New Terminal"));
newTerminal.setIcon(NEW_TERMINAL_ICON.icon());
newTerminal.setToolTip(Tr::tr("Create a new Terminal."));

View File

@@ -68,7 +68,6 @@ private:
QAction nextTerminal;
QAction prevTerminal;
QAction closeTerminal;
QAction lockKeyboard;
QMenu m_shellMenu;

View File

@@ -8,6 +8,8 @@
#include <coreplugin/icore.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <libptyqt/ptyqt.h>
#include <utils/dropsupport.h>
#include <utils/environment.h>
#include <utils/expected.h>
@@ -410,12 +412,23 @@ TerminalSettings::TerminalSettings()
"instead of closing the terminal."));
sendEscapeToTerminal.setDefaultValue(false);
lockKeyboard.setSettingsKey("LockKeyboard");
lockKeyboard.setLabelText(Tr::tr("Block shortcuts in terminal"));
lockKeyboard.setToolTip(
Tr::tr("Keeps Qt Creator short cuts from interfering with the terminal."));
lockKeyboard.setDefaultValue(true);
audibleBell.setSettingsKey("AudibleBell");
audibleBell.setLabelText(Tr::tr("Audible bell"));
audibleBell.setToolTip(Tr::tr("Makes the terminal beep when a bell "
"character is received."));
audibleBell.setDefaultValue(true);
enableMouseTracking.setSettingsKey("EnableMouseTracking");
enableMouseTracking.setLabelText(Tr::tr("Enable mouse tracking"));
enableMouseTracking.setToolTip(Tr::tr("Enables mouse tracking in the terminal."));
enableMouseTracking.setDefaultValue(true);
setupColor(this,
foregroundColor,
"Foreground",
@@ -528,8 +541,10 @@ TerminalSettings::TerminalSettings()
Column {
enableTerminal, st,
sendEscapeToTerminal, st,
lockKeyboard, st,
audibleBell, st,
allowBlinkingCursor, st,
enableMouseTracking, st,
},
},
Group {

View File

@@ -31,6 +31,8 @@ public:
Utils::BoolAspect sendEscapeToTerminal{this};
Utils::BoolAspect audibleBell{this};
Utils::BoolAspect lockKeyboard{this};
Utils::BoolAspect enableMouseTracking{this};
};
TerminalSettings &settings();

View File

@@ -494,6 +494,39 @@ ShellIntegration *TerminalSurface::shellIntegration() const
return d->m_shellIntegration;
}
void TerminalSurface::mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers)
{
vterm_mouse_move(d->m_vterm.get(), pos.y(), pos.x(), Internal::qtModifierToVTerm(modifiers));
}
void TerminalSurface::mouseButton(Qt::MouseButton button,
bool pressed,
Qt::KeyboardModifiers modifiers)
{
int btnIdx = 0;
switch (button) {
case Qt::LeftButton:
btnIdx = 1;
break;
case Qt::RightButton:
btnIdx = 3;
break;
case Qt::MiddleButton:
btnIdx = 2;
break;
case Qt::ExtraButton1:
btnIdx = 4;
break;
case Qt::ExtraButton2:
btnIdx = 5;
break;
default:
return;
}
vterm_mouse_button(d->m_vterm.get(), btnIdx, pressed, Internal::qtModifierToVTerm(modifiers));
}
CellIterator TerminalSurface::begin() const
{
auto res = CellIterator(this, {0, 0});

View File

@@ -95,6 +95,8 @@ public:
ShellIntegration *shellIntegration() const;
void mouseMove(QPoint pos, Qt::KeyboardModifiers modifiers);
void mouseButton(Qt::MouseButton button, bool pressed, Qt::KeyboardModifiers modifiers);
signals:
void writeToPty(const QByteArray &data);
void invalidated(QRect grid);

View File

@@ -1280,6 +1280,14 @@ void TerminalWidget::updateViewportRect(const QRect &rect)
void TerminalWidget::wheelEvent(QWheelEvent *event)
{
verticalScrollBar()->event(event);
if (!settings().enableMouseTracking())
return;
if (event->angleDelta().ry() > 0)
m_surface->mouseButton(Qt::ExtraButton1, true, event->modifiers());
else if (event->angleDelta().ry() < 0)
m_surface->mouseButton(Qt::ExtraButton2, true, event->modifiers());
}
void TerminalWidget::focusInEvent(QFocusEvent *)
@@ -1306,8 +1314,18 @@ void TerminalWidget::inputMethodEvent(QInputMethodEvent *event)
m_surface->sendKey(event->commitString());
}
QPoint TerminalWidget::toGridPos(QMouseEvent *event) const
{
return globalToGrid(event->pos().toPointF() + QPointF(0, -topMargin() + 0.5));
}
void TerminalWidget::mousePressEvent(QMouseEvent *event)
{
if (settings().enableMouseTracking()) {
m_surface->mouseMove(toGridPos(event), event->modifiers());
m_surface->mouseButton(event->button(), true, event->modifiers());
}
m_scrollDirection = 0;
m_activeMouseSelect.start = viewportToGlobal(event->pos());
@@ -1383,8 +1401,12 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
}
}
}
void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
{
if (settings().enableMouseTracking())
m_surface->mouseMove(toGridPos(event), event->modifiers());
if (m_selection && event->buttons() & Qt::LeftButton) {
Selection newSelection = *m_selection;
int scrollVelocity = 0;
@@ -1487,6 +1509,11 @@ bool TerminalWidget::checkLinkAt(const QPoint &pos)
void TerminalWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (settings().enableMouseTracking()) {
m_surface->mouseMove(toGridPos(event), event->modifiers());
m_surface->mouseButton(event->button(), false, event->modifiers());
}
m_scrollTimer.stop();
if (m_selection && event->button() == Qt::LeftButton) {
@@ -1528,6 +1555,12 @@ TerminalWidget::TextAndOffsets TerminalWidget::textAt(const QPoint &pos) const
void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
if (settings().enableMouseTracking()) {
m_surface->mouseMove(toGridPos(event), event->modifiers());
m_surface->mouseButton(event->button(), true, event->modifiers());
m_surface->mouseButton(event->button(), false, event->modifiers());
}
const auto hit = textAt(event->pos());
setSelection(Selection{hit.start, hit.end, true});

View File

@@ -156,6 +156,7 @@ protected:
QPoint globalToGrid(QPointF p) const;
QPointF gridToGlobal(QPoint p, bool bottom = false, bool right = false) const;
QRect gridToViewport(QRect rect) const;
QPoint toGridPos(QMouseEvent *event) const;
void updateViewport();
void updateViewportRect(const QRect &rect);