diff --git a/src/DetachableTabBar.cpp b/src/DetachableTabBar.cpp index 5d30318b..4d2763a8 100644 --- a/src/DetachableTabBar.cpp +++ b/src/DetachableTabBar.cpp @@ -1,217 +1,220 @@ /* Copyright 2018 by Tomaz Canabrava This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "DetachableTabBar.h" #include "KonsoleSettings.h" #include "ViewContainer.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { QString splitDragId(QStringLiteral("konsole/terminal_display")); QString tabDragMime(QStringLiteral("konsole/tab")); } namespace Konsole { DetachableTabBar::DetachableTabBar(QWidget *parent) : QTabBar(parent), dragType(DragType::NONE), _originalCursor(cursor()), tabId(-1), _draggerHandlerPosition(-1) { setAcceptDrops(true); setElideMode(Qt::TextElideMode::ElideMiddle); KAcceleratorManager::setNoAccel(this); } void DetachableTabBar::middleMouseButtonClickAt(const QPoint& pos) { tabId = tabAt(pos); if (tabId != -1) { emit closeTab(tabId); } } void DetachableTabBar::mousePressEvent(QMouseEvent *event) { QTabBar::mousePressEvent(event); _containers = window()->findChildren(); } void DetachableTabBar::mouseMoveEvent(QMouseEvent *event) { QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData(); quintptr data = (quintptr) topLevelWidget(); mimeData->setData(tabDragMime, QByteArray::number(data)); mimeData->setProperty("tabId", tabAt(event->pos())); drag->setMimeData(mimeData); // this is blocking, so the code below will execute only after mouse release. drag->exec(); QWidget *targetWidget = qobject_cast(drag->target()); if (drag->target() == nullptr) { if (count() != 1) { emit detachTab(currentIndex()); setCursor(_originalCursor); } } else if (window() != targetWidget->window()) { if (_containers.size() == 1 || count() > 1) { emit moveTabToWindow(currentIndex(), targetWidget); } } } void DetachableTabBar::mouseReleaseEvent(QMouseEvent *event) { QTabBar::mouseReleaseEvent(event); switch(event->button()) { case Qt::MiddleButton : if (KonsoleSettings::closeTabOnMiddleMouseButton()) { middleMouseButtonClickAt(event->pos()); } tabId = tabAt(event->pos()); if (tabId == -1) { emit newTabRequest(); } break; case Qt::LeftButton: _containers = window()->findChildren(); break; default: break; } setCursor(_originalCursor); if (contentsRect().adjusted(-30,-30,30,30).contains(event->pos())) { return; } } void DetachableTabBar::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat(splitDragId)) { auto other_pid = event->mimeData()->data(splitDragId).toInt(); // don't accept the drop if it's another instance of konsole if (qApp->applicationPid() != other_pid) { return; } event->accept(); } else if (event->mimeData()->hasFormat(tabDragMime)) { event->accept(); } } void DetachableTabBar::dragMoveEvent(QDragMoveEvent* event) { if (event->mimeData()->hasFormat(splitDragId)) { int tabIdx = tabAt(event->pos()); if (tabIdx != -1) { setCurrentIndex(tabIdx); } } else if (event->mimeData()->hasFormat(tabDragMime)) { const int tabIdx = tabAt(event->pos()); const QRect tabSize = tabRect(tabIdx); const int newHandlerPosition = event->pos().x() - tabSize.x() < tabSize.width() / 2 ? tabSize.x() : tabSize.x() + tabSize.width(); if (_draggerHandlerPosition != newHandlerPosition) { _draggerHandlerPosition = newHandlerPosition; update(); } } } void DetachableTabBar::dragLeaveEvent(QDragLeaveEvent* event) { _draggerHandlerPosition = -1; } void DetachableTabBar::dropEvent(QDropEvent *event) { event->acceptProposedAction(); const int originalTab = event->mimeData()->property("tabId").toInt(); - const int thisTab = tabAt(event->pos()); + int thisTab = tabAt(event->pos()); const QRect tabSize = tabRect(thisTab); const int dropPosition = event->pos().x() - tabSize.x() < tabSize.width() / 2 ? Qt::LeftEdge : Qt::RightEdge; _draggerHandlerPosition = -1; qDebug() << "dropping" << originalTab << "at" << thisTab << "on the" << (dropPosition == Qt::LeftEdge ? "Left" : "Right"); if (dropPosition == Qt::LeftEdge && thisTab -1 == originalTab) { qDebug() << "Dropping at the same position on the left"; update(); return; } if (dropPosition == Qt::RightEdge && thisTab +1 == originalTab) { qDebug() << "Dropping at the same potision on the right"; update(); return; } if (originalTab == thisTab) { qDebug() << "Dropping at the same time"; update(); return; } - // There's something wrong with the math here, but already works much better. - moveTab(originalTab, thisTab); + if (originalTab < thisTab) { + thisTab -= 1; + } + + moveTab(originalTab, dropPosition == Qt::LeftEdge ? thisTab : thisTab + 1); _draggerHandlerPosition = -1; } void DetachableTabBar::paintEvent(QPaintEvent* event) { QTabBar::paintEvent(event); if (_draggerHandlerPosition != -1) { QPainter p(this); p.drawPolygon(QPolygon({ {_draggerHandlerPosition - 10, 0}, {_draggerHandlerPosition + 10, 0}, {_draggerHandlerPosition, height()} })); } } }