From kde-commits Wed Mar 18 18:30:54 2009 From: Eike Hein Date: Wed, 18 Mar 2009 18:30:54 +0000 To: kde-commits Subject: extragear/utils/yakuake Message-Id: <1237401054.005575.29331.nullmailer () svn ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=123740106519906 SVN commit 941035 by hein: Add support for moving tabs on the tab bar by drag and drop. Patch by Juan Carlos Torres. M +1 -0 ChangeLog M +2 -0 app/main.cpp M +280 -52 app/tabbar.cpp M +17 -1 app/tabbar.h --- trunk/extragear/utils/yakuake/ChangeLog #941034:941035 @@ -7,6 +7,7 @@ * Added an option to open the application window after program start. * Slightly improved options layout on the Behavior page of the configura- tion dialog. +* Added support for moving tabs on the tab bar by drag and drop. Changes in 2.9.4: --- trunk/extragear/utils/yakuake/app/main.cpp #941034:941035 @@ -59,6 +59,8 @@ ki18nc("@info:credit", "Project Founder, Default skin (Inactive)")); aboutData.addCredit(ki18nc("@info:credit", "Daniel 'suslik' D."), ki18nc("@info:credit", "Plastik skin"), "dd@accentsolution.com"); + aboutData.addCredit(ki18nc("@info:credit", "Juan Carlos Torres"), + ki18nc("@info:credit", "Tab bar drag and drop support"), "carlosdgtorres@gmail.com"); KCmdLineArgs::init(argc, argv, &aboutData); --- trunk/extragear/utils/yakuake/app/tabbar.cpp #941034:941035 @@ -33,7 +33,11 @@ #include #include +#include +#include +#include + TabBar::TabBar(MainWindow* mainWindow) : QWidget(mainWindow) { QDBusConnection::sessionBus().registerObject("/yakuake/tabs", this, QDBusConnection::ExportScriptableSlots); @@ -46,6 +50,8 @@ m_mousePressed = false; m_mousePressedIndex = -1; + + m_dropIndicator = 0; m_mainWindow = mainWindow; m_skin = mainWindow->skin(); @@ -78,6 +84,8 @@ connect(m_lineEdit, SIGNAL(editingFinished()), m_lineEdit, SLOT(hide())); connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(renameTab())); + + setAcceptDrops(true); } TabBar::~TabBar() @@ -179,63 +187,16 @@ QPainter painter(this); painter.setPen(m_skin->tabBarTextColor()); - QString title; - int sessionId; - bool selected; int x = m_skin->tabBarPosition().x(); int y = m_skin->tabBarPosition().y(); - QFont font = KGlobalSettings::generalFont(); - int textWidth = 0; m_tabWidths.clear(); - + QRect tabsClipRect(x, y, m_closeTabButton->x() - x, height() - y); painter.setClipRect(tabsClipRect); for (int index = 0; index < m_tabs.size(); ++index) { - sessionId = m_tabs.at(index); - selected = (sessionId == m_selectedSessionId); - title = m_tabTitles[sessionId]; - - if (selected) - { - painter.drawPixmap(x, y, m_skin->tabBarSelectedLeftCornerImage()); - x += m_skin->tabBarSelectedLeftCornerImage().width(); - } - else if (index != m_tabs.indexOf(m_selectedSessionId) + 1) - { - painter.drawPixmap(x, y, m_skin->tabBarSeparatorImage()); - x += m_skin->tabBarSeparatorImage().width(); - } - - if (selected) font.setBold(true); - else font.setBold(false); - - painter.setFont(font); - - QFontMetrics fontMetrics(font); - textWidth = fontMetrics.width(title) + 10; - - if (selected) - painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarSelectedBackgroundImage()); - else - painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarUnselectedBackgroundImage()); - - painter.drawText(x, y, textWidth + 1, height() + 2, Qt::AlignHCenter | Qt::AlignVCenter, title); - - x += textWidth; - - if (selected) - { - painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSelectedRightCornerImage()); - x += m_skin->tabBarSelectedRightCornerImage().width(); - } - else if (index != m_tabs.indexOf(m_selectedSessionId) - 1) - { - painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSeparatorImage()); - x += m_skin->tabBarSeparatorImage().width(); - } - + x = drawButton(x, y, index, painter); m_tabWidths << x; } @@ -268,6 +229,60 @@ painter.end(); } +int TabBar::drawButton(int x, int y, int index, QPainter& painter) +{ + QString title; + int sessionId; + bool selected; + QFont font = KGlobalSettings::generalFont(); + int textWidth = 0; + + sessionId = m_tabs.at(index); + selected = (sessionId == m_selectedSessionId); + title = m_tabTitles[sessionId]; + + if (selected) + { + painter.drawPixmap(x, y, m_skin->tabBarSelectedLeftCornerImage()); + x += m_skin->tabBarSelectedLeftCornerImage().width(); + } + else if (index != m_tabs.indexOf(m_selectedSessionId) + 1) + { + painter.drawPixmap(x, y, m_skin->tabBarSeparatorImage()); + x += m_skin->tabBarSeparatorImage().width(); + } + + if (selected) font.setBold(true); + else font.setBold(false); + + painter.setFont(font); + + QFontMetrics fontMetrics(font); + textWidth = fontMetrics.width(title) + 10; + + if (selected) + painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarSelectedBackgroundImage()); + else + painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarUnselectedBackgroundImage()); + + painter.drawText(x, y, textWidth + 1, height() + 2, Qt::AlignHCenter | Qt::AlignVCenter, title); + + x += textWidth; + + if (selected) + { + painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSelectedRightCornerImage()); + x += m_skin->tabBarSelectedRightCornerImage().width(); + } + else if (index != m_tabs.indexOf(m_selectedSessionId) - 1) + { + painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSeparatorImage()); + x += m_skin->tabBarSeparatorImage().width(); + } + + return x; +} + int TabBar::tabAt(int x) { for (int index = 0; index < m_tabWidths.size(); ++index) @@ -305,10 +320,14 @@ if (index == -1) return; - if (event->button() == Qt::LeftButton && index != m_tabs.indexOf(m_selectedSessionId)) + if (event->button() == Qt::LeftButton) { - m_mousePressed = true; - m_mousePressedIndex = index; + m_startPos = event->pos(); + if (index != m_tabs.indexOf(m_selectedSessionId)) + { + m_mousePressed = true; + m_mousePressedIndex = index; + } } QWidget::mousePressEvent(event); @@ -333,6 +352,103 @@ QWidget::mouseReleaseEvent(event); } +void TabBar::mouseMoveEvent(QMouseEvent* event) +{ + if (event->buttons() & Qt::LeftButton) + { + int distance = (event->pos() - m_startPos).manhattanLength(); + if (distance >= KGlobalSettings::dndEventDelay()) + { + int index = tabAt(event->x()); + if (index >= 0) + startDrag(index); + } + } + + QWidget::mouseMoveEvent(event); +} + +void TabBar::dragEnterEvent(QDragEnterEvent* event) +{ + TabBar* eventSource = qobject_cast(event->source()); + + if (eventSource) + { + event->setDropAction(Qt::MoveAction); + event->acceptProposedAction(); + } + else + { + drawDropIndicator(-1); + event->ignore(); + } + + return; +} + +void TabBar::dragMoveEvent(QDragMoveEvent* event) +{ + TabBar* eventSource = qobject_cast(event->source()); + + if (eventSource && event->pos().x() > m_skin->tabBarPosition().x() && event->pos().x() < m_closeTabButton->x()) + { + int index = dropIndex(event->pos()); + + if (index == -1) + index = m_tabs.size(); + + drawDropIndicator(index, isSameTab(event)); + + event->setDropAction(Qt::MoveAction); + event->accept(); + } + else + { + drawDropIndicator(-1); + event->ignore(); + } + + return; +} + +void TabBar::dragLeaveEvent(QDragLeaveEvent* event) +{ + drawDropIndicator(-1); + event->ignore(); + + return; +} + +void TabBar::dropEvent(QDropEvent* event) +{ + drawDropIndicator(-1); + + int x = event->pos().x(); + + if (isSameTab(event) || x < m_skin->tabBarPosition().x() || x > m_closeTabButton->x()) + event->ignore(); + else + { + int targetIndex = dropIndex(event->pos()); + int sourceSessionId = event->mimeData()->text().toInt(); + int sourceIndex = m_tabs.indexOf(sourceSessionId); + + if (targetIndex == -1) + targetIndex = m_tabs.size() - 1; + else if (targetIndex < 0) + targetIndex = 0; + else if (sourceIndex < targetIndex) + --targetIndex; + + m_tabs.move(sourceIndex, targetIndex); + selectTab(sourceSessionId); + + event->accept(); + } + + return; +} + void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { if (QWhatsThis::inWhatsThisMode()) return; @@ -357,6 +473,8 @@ void TabBar::leaveEvent(QEvent* event) { m_mousePressed = false; + drawDropIndicator(-1); + event->ignore(); QWidget::leaveEvent(event); } @@ -517,6 +635,7 @@ int TabBar::sessionAtTab(int index) { + for (int i = 0; i < m_tabs.size(); ++i) { if (i == index) return m_tabs.at(i); @@ -571,3 +690,112 @@ return i18nc("@title:tab", "Shell No. %1", id+1); } } + +void TabBar::startDrag(int index) +{ + int sessionId = sessionAtTab(index); + + // if (sessionId < 0) return; + + int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); + int tabWidth = m_tabWidths.at(index) - x; + QString title = tabTitle(sessionId); + + QPixmap tab(tabWidth, height()); + tab.fill(Qt::transparent); + + QPainter painter(&tab); + painter.initFrom(this); + painter.setPen(m_skin->tabBarTextColor()); + drawButton(0, 0, index, painter); + painter.end(); + + QMimeData* mimeData = new QMimeData; + mimeData->setText(QVariant(sessionId).toString()); + + QDrag* drag = new QDrag(this); + drag->setMimeData(mimeData); + drag->setPixmap(tab); + drag->exec(Qt::MoveAction); + + return; +} + +void TabBar::drawDropIndicator(int index, bool disabled) +{ + const int arrowSize = 16; + + if (!m_dropIndicator) + { + m_dropIndicator = new QLabel(parentWidget()); + m_dropIndicator->resize(arrowSize, arrowSize); + } + + QIcon::Mode drawMode = disabled ? QIcon::Disabled : QIcon::Normal; + m_dropIndicator->setPixmap(KIcon("arrow-down").pixmap(arrowSize, arrowSize, drawMode)); + + if (index < 0) + { + m_dropIndicator->hide(); + return; + } + + int temp_index; + if (index == m_tabs.size()) + temp_index = index - 1; + else + temp_index = index; + + int x = temp_index ? m_tabWidths.at(temp_index - 1) : m_skin->tabBarPosition().x(); + int tabWidth = m_tabWidths.at(temp_index) - x; + int y = m_skin->tabBarPosition().y(); + + m_dropRect = QRect(x, y - height(), tabWidth, height() - y); + QPoint pos; + + if (index < m_tabs.size()) + pos = m_dropRect.topLeft(); + else + pos = m_dropRect.topRight(); + + pos.rx() -= arrowSize/2; + + m_dropIndicator->move(mapTo(parentWidget(),pos)); + m_dropIndicator->show(); + + return; +} + +int TabBar::dropIndex(const QPoint pos) +{ + int index = tabAt(pos.x()); + if (index < 0) + return index; + + int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); + int tabWidth = m_tabWidths.at(index) - x; + int y = m_skin->tabBarPosition().y(); + m_dropRect = QRect(x, y - height(), tabWidth, height() - y); + + if ((pos.x()-m_dropRect.left()) > (m_dropRect.width()/2)) + ++index; + + if (index == m_tabs.size()) + return -1; + + return index; +} + +bool TabBar::isSameTab(const QDropEvent* event) +{ + int index = dropIndex(event->pos()); + int sourceSessionId = event->mimeData()->text().toInt(); + int sourceIndex = m_tabs.indexOf(sourceSessionId); + + bool isLastTab = (sourceIndex == m_tabs.size()-1) && (index == -1); + + if ((sourceIndex == index) || (sourceIndex == index-1) || isLastTab) + return true; + else + return false; +} --- trunk/extragear/utils/yakuake/app/tabbar.h #941034:941035 @@ -27,7 +27,6 @@ #include #include - class MainWindow; class Skin; @@ -37,6 +36,7 @@ class KPushButton; class QToolButton; +class QLabel; class TabBar : public QWidget @@ -84,6 +84,11 @@ virtual void keyPressEvent(QKeyEvent*); virtual void mousePressEvent(QMouseEvent*); virtual void mouseReleaseEvent(QMouseEvent*); + virtual void mouseMoveEvent(QMouseEvent*); + virtual void dragMoveEvent(QDragMoveEvent*); + virtual void dragEnterEvent(QDragEnterEvent*); + virtual void dragLeaveEvent(QDragLeaveEvent*); + virtual void dropEvent(QDropEvent*); virtual void mouseDoubleClickEvent(QMouseEvent*); virtual void contextMenuEvent(QContextMenuEvent*); virtual void leaveEvent(QEvent*); @@ -102,6 +107,13 @@ int tabAt(int x); void updateMoveActions(int index); + + int drawButton(int x, int y, int index, QPainter& painter); + + void startDrag(int index); + void drawDropIndicator(int index, bool disabled = false); + int dropIndex(const QPoint pos); + bool isSameTab(const QDropEvent*); MainWindow* m_mainWindow; Skin* m_skin; @@ -123,6 +135,10 @@ int m_mousePressed; int m_mousePressedIndex; + + QPoint m_startPos; + QLabel* m_dropIndicator; + QRect m_dropRect; }; #endif