From 66e33b9b3951ac4b2aeaf253e61c3de57430e5e1 Mon Sep 17 00:00:00 2001 From: shaojun Date: Thu, 29 Aug 2019 20:21:36 +0800 Subject: [PATCH] feat(appItem):drop application to dock, drag appitem to undock --- frame/controller/dockitemmanager.cpp | 8 +- frame/controller/dockitemmanager.h | 1 + frame/panel/mainpanelcontrol.cpp | 221 +++++++++++++++++++++++++-- frame/panel/mainpanelcontrol.h | 19 +++ frame/window/mainwindow.cpp | 17 ++- frame/window/mainwindow.h | 4 +- 6 files changed, 252 insertions(+), 18 deletions(-) diff --git a/frame/controller/dockitemmanager.cpp b/frame/controller/dockitemmanager.cpp index fa916dc5f..7e437b52a 100644 --- a/frame/controller/dockitemmanager.cpp +++ b/frame/controller/dockitemmanager.cpp @@ -179,6 +179,11 @@ void DockItemManager::itemMoved(DockItem *const sourceItem, DockItem *const targ refreshFSTItemSpliterVisible(); } +void DockItemManager::itemAdded(const QString &appDesktop, int idx) +{ + m_appInter->RequestDock(appDesktop, idx); +} + void DockItemManager::itemDroppedIntoContainer(DockItem *const item) { Q_ASSERT(item->itemType() == DockItem::Plugins || item->itemType() == DockItem::TrayPlugin); @@ -235,8 +240,7 @@ void DockItemManager::refreshFSTItemSpliterVisible() void DockItemManager::appItemAdded(const QDBusObjectPath &path, const int index) { - // the first index is launcher item - int insertIndex = 1; + int insertIndex = 0; // -1 for append to app list end if (index != -1) { diff --git a/frame/controller/dockitemmanager.h b/frame/controller/dockitemmanager.h index 3a95f0394..76b6ebc8e 100644 --- a/frame/controller/dockitemmanager.h +++ b/frame/controller/dockitemmanager.h @@ -63,6 +63,7 @@ public slots: void sortPluginItems(); void updatePluginsItemOrderKey(); void itemMoved(DockItem *const sourceItem, DockItem *const targetItem); + void itemAdded(const QString &appDesktop, int idx); void itemDroppedIntoContainer(DockItem *const item); void itemDragOutFromContainer(DockItem *const item); void refreshFSTItemSpliterVisible(); diff --git a/frame/panel/mainpanelcontrol.cpp b/frame/panel/mainpanelcontrol.cpp index 5061493e8..b5ff9ff79 100644 --- a/frame/panel/mainpanelcontrol.cpp +++ b/frame/panel/mainpanelcontrol.cpp @@ -22,6 +22,9 @@ #include "mainpanelcontrol.h" #include "../item/dockitem.h" #include "util/docksettings.h" +#include "../item/placeholderitem.h" +#include "../item/components/appdrag.h" +#include "../item/appitem.h" #include @@ -43,6 +46,8 @@ MainPanelControl::MainPanelControl(QWidget *parent) , m_appAreaSonWidget(new QWidget(this)) , m_appAreaSonLayout(new QBoxLayout(QBoxLayout::LeftToRight)) , m_position(Qt::TopEdge) + , m_placeholderItem(nullptr) + , m_appDragWidget(nullptr) { init(); updateMainPanelLayout(); @@ -218,6 +223,7 @@ void MainPanelControl::insertItem(const int index, DockItem *item) addFixedAreaItem(index, item); break; case DockItem::App: + case DockItem::Placeholder: addAppAreaItem(index, item); break; case DockItem::TrayPlugin: @@ -230,6 +236,7 @@ void MainPanelControl::insertItem(const int index, DockItem *item) break; } + updateMainPanelLayout(); updateAppAreaSonWidgetSize(); } @@ -240,6 +247,7 @@ void MainPanelControl::removeItem(DockItem *item) removeFixedAreaItem(item); break; case DockItem::App: + case DockItem::Placeholder: removeAppAreaItem(item); break; case DockItem::TrayPlugin: @@ -255,6 +263,16 @@ void MainPanelControl::removeItem(DockItem *item) updateAppAreaSonWidgetSize(); } +MainPanelDelegate *MainPanelControl::delegate() const +{ + return m_delegate; +} + +void MainPanelControl::setDelegate(MainPanelDelegate *delegate) +{ + m_delegate = delegate; +} + void MainPanelControl::moveItem(DockItem *sourceItem, DockItem *targetItem) { // get target index @@ -275,18 +293,118 @@ void MainPanelControl::moveItem(DockItem *sourceItem, DockItem *targetItem) void MainPanelControl::dragEnterEvent(QDragEnterEvent *e) { + DockItem *sourceItem = qobject_cast(e->source()); + if (sourceItem) { + e->accept(); + return; + } + + // 拖app到dock上 + const char *RequestDockKey = "RequestDock"; + const char *RequestDockKeyFallback = "text/plain"; + const char *DesktopMimeType = "application/x-desktop"; + + m_draggingMimeKey = e->mimeData()->formats().contains(RequestDockKey) ? RequestDockKey : RequestDockKeyFallback; + + // dragging item is NOT a desktop file + if (QMimeDatabase().mimeTypeForFile(e->mimeData()->data(m_draggingMimeKey)).name() != DesktopMimeType) { + m_draggingMimeKey.clear(); + qDebug() << "dragging item is NOT a desktop file"; + return; + } + + if (m_delegate && m_delegate->appIsOnDock(e->mimeData()->data(m_draggingMimeKey))) + return; + e->accept(); } -void MainPanelControl::dragMoveEvent(QDragMoveEvent *e) +void MainPanelControl::dragLeaveEvent(QDragLeaveEvent *e) { + if (m_placeholderItem) { + const QRect r(static_cast(parent())->pos(), size()); + const QPoint p(QCursor::pos()); + + // remove margins to fix a touch screen bug: + // the mouse point position will stay on this rect's margins after + // drag move to the edge of screen + if (r.marginsRemoved(QMargins(1, 10, 1, 1)).contains(p)) + return; + + removeAppAreaItem(m_placeholderItem); + m_placeholderItem->deleteLater(); + updateMainPanelLayout(); + } +} + +void MainPanelControl::dropEvent(QDropEvent *e) +{ + if (m_placeholderItem) { + + emit itemAdded(e->mimeData()->data(m_draggingMimeKey), m_appAreaSonLayout->indexOf(m_placeholderItem)); + + removeAppAreaItem(m_placeholderItem); + m_placeholderItem->deleteLater(); + } +} + +void MainPanelControl::handleDragMove(QDragMoveEvent *e, bool isFilter) +{ + if (!e->source()) { + // 应用程序拖到dock上 + e->accept(); + + DockItem *insertPositionItem = dropTargetItem(nullptr, e->pos()); + + if (m_placeholderItem.isNull()) { + + m_placeholderItem = new PlaceholderItem; + + if (m_position == Qt::TopEdge || m_position == Qt::BottomEdge) { + if (m_appAreaSonWidget->mapFromParent(e->pos()).x() > m_appAreaSonWidget->rect().right()) { + // 插入到最右侧 + insertPositionItem = nullptr; + } + } else { + if (m_appAreaSonWidget->mapFromParent(e->pos()).y() > m_appAreaSonWidget->rect().bottom()) { + // 插入到最下测 + insertPositionItem = nullptr; + } + } + + insertItem(m_appAreaSonLayout->indexOf(insertPositionItem), m_placeholderItem); + + } else if (insertPositionItem && m_placeholderItem != insertPositionItem) { + moveItem(m_placeholderItem, insertPositionItem); + } + + return; + } + DockItem *sourceItem = qobject_cast(e->source()); + if (!sourceItem) { e->ignore(); return; } - DockItem *targetItem = dropTargetItem(sourceItem, e->pos()); + DockItem *targetItem = nullptr; + + if (isFilter) { + // appItem调整顺序或者移除驻留 + targetItem = dropTargetItem(sourceItem, mapFromGlobal(m_appDragWidget->mapToGlobal(e->pos()))); + + if (targetItem) { + m_appDragWidget->setOriginPos((m_appAreaSonWidget->mapToGlobal(targetItem->pos()))); + } else { + targetItem = sourceItem; + } + + } else { + // other dockItem调整顺序 + targetItem = dropTargetItem(sourceItem, e->pos()); + } + if (!targetItem) { e->ignore(); return; @@ -301,8 +419,27 @@ void MainPanelControl::dragMoveEvent(QDragMoveEvent *e) emit itemMoved(sourceItem, targetItem); } +void MainPanelControl::dragMoveEvent(QDragMoveEvent *e) +{ + handleDragMove(e, false); +} + bool MainPanelControl::eventFilter(QObject *watched, QEvent *event) { + if (m_appDragWidget && watched == static_cast(m_appDragWidget)->viewport()) { + QDropEvent *e = static_cast(event); + bool isContains = rect().contains(mapFromGlobal(m_appDragWidget->mapToGlobal(e->pos()))); + if (isContains) { + if (event->type() == QEvent::DragMove) { + handleDragMove(static_cast(event), true); + } else if (event->type() == QEvent::Drop) { + m_appDragWidget->hide(); + return true; + } + } + return false; + } + if (event->type() != QEvent::MouseMove) return false; @@ -329,29 +466,59 @@ void MainPanelControl::startDrag(DockItem *item) item->setDraging(true); item->update(); - QDrag *drag = new QDrag(item); - drag->setPixmap(pixmap); + QDrag *drag = nullptr; + if (item->itemType() == DockItem::App) { + AppDrag *appDrag = new AppDrag(item); + appDrag->setPixmap(pixmap); + m_appDragWidget = appDrag->appDragWidget(); + + connect(m_appDragWidget, &AppDragWidget::destroyed, this, [ = ] { + m_appDragWidget = nullptr; + }); + + m_appDragWidget->show(); + + Dock::Position position; + switch (m_position) { + case Qt::TopEdge: position = Dock::Top; break; + case Qt::BottomEdge: position = Dock::Bottom; break; + case Qt::LeftEdge: position = Dock::Left; break; + case Qt::RightEdge: position = Dock::Right; break; + } + + appDrag->appDragWidget()->setOriginPos((m_appAreaSonWidget->mapToGlobal(item->pos()))); + appDrag->appDragWidget()->setDockInfo(position, QRect(mapToGlobal(pos()), size())); + static_cast(m_appDragWidget)->viewport()->installEventFilter(this); + + drag = appDrag; + } else { + drag = new QDrag(item); + drag->setPixmap(pixmap); + } drag->setHotSpot(pixmap.rect().center() / pixmap.devicePixelRatioF()); drag->setMimeData(new QMimeData); drag->exec(Qt::MoveAction); + m_appDragWidget = nullptr; item->setDraging(false); item->update(); } DockItem *MainPanelControl::dropTargetItem(DockItem *sourceItem, QPoint point) { - QWidget *parentWidget = nullptr; + QWidget *parentWidget = m_appAreaSonWidget; - switch (sourceItem->itemType()) { - case DockItem::App: - parentWidget = m_appAreaSonWidget; - break; - case DockItem::Plugins: - parentWidget = m_pluginAreaWidget; - break; - default: - break; + if (sourceItem) { + switch (sourceItem->itemType()) { + case DockItem::App: + parentWidget = m_appAreaSonWidget; + break; + case DockItem::Plugins: + parentWidget = m_pluginAreaWidget; + break; + default: + break; + } } if (!parentWidget) @@ -378,5 +545,31 @@ DockItem *MainPanelControl::dropTargetItem(DockItem *sourceItem, QPoint point) } } + if (!targetItem && parentWidget == m_appAreaSonWidget) { + // appitem调整顺序是,判断是否拖放在两边空白区域 + + if (!m_appAreaSonLayout->count()) + return targetItem; + + DockItem *first = qobject_cast(m_appAreaSonLayout->itemAt(0)->widget()); + DockItem *last = qobject_cast(m_appAreaSonLayout->itemAt(m_appAreaSonLayout->count() - 1)->widget()); + + if (m_position == Qt::TopEdge || m_position == Qt::BottomEdge) { + + if (point.x() < 0) { + targetItem = first; + } else { + targetItem = last; + } + } else { + + if (point.y() < 0) { + targetItem = first; + } else { + targetItem = last; + } + } + + } return targetItem; } diff --git a/frame/panel/mainpanelcontrol.h b/frame/panel/mainpanelcontrol.h index 049229f77..1c86eec8b 100644 --- a/frame/panel/mainpanelcontrol.h +++ b/frame/panel/mainpanelcontrol.h @@ -29,7 +29,15 @@ using namespace Dock; +class MainPanelDelegate +{ +public: + virtual bool appIsOnDock(const QString &appDesktop) = 0; +}; + class DockItem; +class PlaceholderItem; +class AppDragWidget; class MainPanelControl : public QWidget { Q_OBJECT @@ -48,8 +56,12 @@ public: void setPositonValue(const Qt::Edge val); void updateDisplayMode(DisplayMode m_displayMode); + MainPanelDelegate *delegate() const; + void setDelegate(MainPanelDelegate *delegate); + signals: void itemMoved(DockItem *sourceItem, DockItem *targetItem); + void itemAdded(const QString &appDesktop, int idx); private: void resizeEvent(QResizeEvent *event) override; @@ -60,11 +72,14 @@ private: void dragMoveEvent(QDragMoveEvent *e) override; void dragEnterEvent(QDragEnterEvent *e) override; + void dragLeaveEvent(QDragLeaveEvent *e); + void dropEvent(QDropEvent *) override; bool eventFilter(QObject *watched, QEvent *event) override; void startDrag(DockItem *); DockItem *dropTargetItem(DockItem *sourceItem, QPoint point); void moveItem(DockItem *sourceItem, DockItem *targetItem); + void handleDragMove(QDragMoveEvent *e, bool isFilter); public slots: void insertItem(const int index, DockItem *item); @@ -82,6 +97,10 @@ private: QWidget *m_appAreaSonWidget; QBoxLayout *m_appAreaSonLayout; Qt::Edge m_position; + QPointer m_placeholderItem; + MainPanelDelegate *m_delegate; + QString m_draggingMimeKey; + AppDragWidget *m_appDragWidget; }; #endif // MAINPANELCONTROL_H diff --git a/frame/window/mainwindow.cpp b/frame/window/mainwindow.cpp index 5c6d2bc9d..a5f1f6a61 100644 --- a/frame/window/mainwindow.cpp +++ b/frame/window/mainwindow.cpp @@ -113,6 +113,7 @@ MainWindow::MainWindow(QWidget *parent) resizeMainPanelWindow(); + m_mainPanel->setDelegate(this); for (auto item : DockItemManager::instance()->itemList()) m_mainPanel->insertItem(-1, item); } @@ -417,6 +418,7 @@ void MainWindow::initConnections() connect(DockItemManager::instance(), &DockItemManager::requestRefershWindowVisible, this, &MainWindow::updatePanelVisible, Qt::QueuedConnection); connect(DockItemManager::instance(), &DockItemManager::requestWindowAutoHide, m_settings, &DockSettings::setAutoHide); connect(m_mainPanel, &MainPanelControl::itemMoved, DockItemManager::instance(), &DockItemManager::itemMoved, Qt::DirectConnection); + connect(m_mainPanel, &MainPanelControl::itemAdded, DockItemManager::instance(), &DockItemManager::itemAdded, Qt::DirectConnection); } @@ -499,7 +501,15 @@ void MainWindow::updateGeometry() // DockDisplayMode and DockPosition MUST be set before invoke setFixedSize method of MainPanel // m_mainPanel->updateDockDisplayMode(m_settings->displayMode()); -// m_mainPanel->updateDockPosition(position); + + Qt::Edge panelPos; + switch (position) { + case Dock::Top: panelPos = Qt::TopEdge; break; + case Dock::Bottom: panelPos = Qt::BottomEdge; break; + case Dock::Left: panelPos = Qt::LeftEdge; break; + case Dock::Right: panelPos = Qt::RightEdge; break; + } + m_mainPanel->setPositonValue(panelPos); // this->setFixedSize has been overridden for size animation resizeMainPanelWindow(); @@ -886,6 +896,11 @@ QRect MainWindow::getNoneResizeRegion() return r; } +bool MainWindow::appIsOnDock(const QString &appDesktop) +{ + return DockItemManager::instance()->appIsOnDock(appDesktop); +} + void MainWindow::resizeMainWindow() { const Position position = m_settings->position(); diff --git a/frame/window/mainwindow.h b/frame/window/mainwindow.h index da99d23f8..5be2692b8 100644 --- a/frame/window/mainwindow.h +++ b/frame/window/mainwindow.h @@ -27,6 +27,7 @@ #include "dbus/dbusdockadaptors.h" #include "dbus/sni/statusnotifierwatcher_interface.h" #include "util/docksettings.h" +#include "panel/mainpanelcontrol.h" #include #include @@ -41,7 +42,7 @@ DWIDGET_USE_NAMESPACE class MainPanel; class MainPanelControl; class DBusDockAdaptors; -class MainWindow : public DBlurEffectWidget +class MainWindow : public DBlurEffectWidget, public MainPanelDelegate { Q_OBJECT @@ -81,6 +82,7 @@ private: void x11MoveWindow(const int x, const int y); void x11MoveResizeWindow(const int x, const int y, const int w, const int h); QRect getNoneResizeRegion(); + bool appIsOnDock(const QString &appDesktop); signals: void panelGeometryChanged();