From 88fceb9589b6ff36b8ad0c48f3def861555db4a4 Mon Sep 17 00:00:00 2001 From: listenerri Date: Mon, 4 Jun 2018 21:09:41 +0800 Subject: [PATCH] add: drag drop app item animation Change-Id: I9ca4f97ac4a1227bef0f9cd856ac52b66de4465d --- frame/item/appitem.cpp | 50 ++++-- frame/item/appitem.h | 10 ++ frame/item/components/appdrag.cpp | 64 +++++++ frame/item/components/appdrag.h | 52 ++++++ frame/item/components/appdragwidget.cpp | 213 ++++++++++++++++++++++++ frame/item/components/appdragwidget.h | 74 ++++++++ frame/panel/mainpanel.cpp | 124 +++++++++----- frame/panel/mainpanel.h | 8 +- 8 files changed, 539 insertions(+), 56 deletions(-) create mode 100644 frame/item/components/appdrag.cpp create mode 100644 frame/item/components/appdrag.h create mode 100644 frame/item/components/appdragwidget.cpp create mode 100644 frame/item/components/appdragwidget.h diff --git a/frame/item/appitem.cpp b/frame/item/appitem.cpp index 1f8881a18..c872f1822 100644 --- a/frame/item/appitem.cpp +++ b/frame/item/appitem.cpp @@ -4,6 +4,7 @@ * Author: sbw * * Maintainer: sbw + * listenerri * * 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 @@ -53,6 +54,10 @@ AppItem::AppItem(const QDBusObjectPath &entry, QWidget *parent) m_swingEffectView(nullptr), m_itemAnimation(nullptr), + m_wmHelper(DWindowManagerHelper::instance()), + + m_drag(nullptr), + m_dragging(false), m_appIcon(QPixmap()), @@ -139,6 +144,21 @@ int AppItem::itemBaseWidth() return itemBaseHeight() * 1.4; } +void AppItem::undock() +{ + m_itemEntryInter->RequestUndock(); +} + +QWidget *AppItem::appDragWidget() +{ + return static_cast(m_drag)->appDragWidget(); +} + +void AppItem::setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry) +{ + static_cast(m_drag)->appDragWidget()->setDockInfo(dockPosition, dockGeometry); +} + void AppItem::moveEvent(QMoveEvent *e) { DockItem::moveEvent(e); @@ -425,18 +445,28 @@ void AppItem::startDrag() const QPixmap &dragPix = m_appIcon; - QDrag *drag = new QDrag(this); - drag->setPixmap(dragPix); - drag->setHotSpot(dragPix.rect().center() / dragPix.devicePixelRatioF()); - drag->setMimeData(new QMimeData); + m_drag = new AppDrag(this); + m_drag->setMimeData(new QMimeData); - emit dragStarted(); - const Qt::DropAction result = drag->exec(Qt::MoveAction); - Q_UNUSED(result); + if (m_wmHelper->hasComposite()) { + m_drag->setPixmap(dragPix); + emit dragStarted(); + m_drag->exec(Qt::MoveAction); + } else { + m_drag->QDrag::setPixmap(dragPix); + m_drag->setHotSpot(dragPix.rect().center() / dragPix.devicePixelRatioF()); + emit dragStarted(); + m_drag->QDrag::exec(Qt::MoveAction); + } - // drag out of dock panel - if (!drag->target()) - m_itemEntryInter->RequestUndock(); + // MainPanel will put this item to Item-Container when received this signal(MainPanel::itemDropped) + //emit itemDropped(m_drag->target()); + + if (!m_wmHelper->hasComposite()) { + if (!m_drag->target()) { + m_itemEntryInter->RequestUndock(); + } + } m_dragging = false; setVisible(true); diff --git a/frame/item/appitem.h b/frame/item/appitem.h index acbb44594..a4e127890 100644 --- a/frame/item/appitem.h +++ b/frame/item/appitem.h @@ -4,6 +4,7 @@ * Author: sbw * * Maintainer: sbw + * listenerri * * 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 @@ -24,6 +25,7 @@ #include "dockitem.h" #include "components/previewcontainer.h" +#include "components/appdrag.h" #include "dbus/dbusclientmanager.h" #include "../widgets/tipswidget.h" @@ -49,6 +51,9 @@ public: static int iconBaseSize(); static int itemBaseHeight(); static int itemBaseWidth(); + void undock(); + QWidget *appDragWidget(); + void setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry); inline ItemType itemType() const { return App; } @@ -56,6 +61,7 @@ signals: void requestActivateWindow(const WId wid) const; void requestPreviewWindow(const WId wid) const; void requestCancelPreview() const; + void dragReady(QWidget *dragWidget); private: void moveEvent(QMoveEvent *e) override; @@ -97,6 +103,10 @@ private: QGraphicsView *m_swingEffectView; QGraphicsItemAnimation *m_itemAnimation; + DWindowManagerHelper *m_wmHelper; + + AppDrag *m_drag; + bool m_dragging; bool m_active; WindowInfoMap m_windowInfos; diff --git a/frame/item/components/appdrag.cpp b/frame/item/components/appdrag.cpp new file mode 100644 index 000000000..c5b8fd0c4 --- /dev/null +++ b/frame/item/components/appdrag.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: listenerri + * + * Maintainer: listenerri + * + * 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 3 of the License, or + * 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, see . + */ + +#include "appdrag.h" + +AppDrag::AppDrag(QObject *dragSource) : QDrag(dragSource) +{ + // delete by itself + m_appDragWidget = new AppDragWidget; +} + +AppDrag::~AppDrag() { } + +void AppDrag::setPixmap(const QPixmap &pix) +{ + m_appDragWidget->setAppPixmap(pix); +} + +QPixmap AppDrag::pixmap() const +{ + /* TODO: return pixmap */ + return QPixmap(); +} + +Qt::DropAction AppDrag::start(Qt::DropActions supportedActions) +{ + m_appDragWidget->show(); + return QDrag::start(supportedActions); +} + +Qt::DropAction AppDrag::exec(Qt::DropActions supportedActions) +{ + m_appDragWidget->show(); + return QDrag::exec(supportedActions); +} + +Qt::DropAction AppDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultAction) +{ + m_appDragWidget->show(); + return QDrag::exec(supportedActions, defaultAction); +} + +AppDragWidget *AppDrag::appDragWidget() +{ + return m_appDragWidget; +} diff --git a/frame/item/components/appdrag.h b/frame/item/components/appdrag.h new file mode 100644 index 000000000..68719962e --- /dev/null +++ b/frame/item/components/appdrag.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: listenerri + * + * Maintainer: listenerri + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef APPDRAG_H +#define APPDRAG_H + +#include "appdragwidget.h" + +#include +#include + +class AppDrag : public QDrag +{ +public: + AppDrag(QObject *dragSource); + virtual ~AppDrag(); + + void setPixmap(const QPixmap &); + QPixmap pixmap() const; + + Qt::DropAction start(Qt::DropActions supportedActions = Qt::CopyAction); + Qt::DropAction exec(Qt::DropActions supportedActions = Qt::MoveAction); + Qt::DropAction exec(Qt::DropActions supportedActions, Qt::DropAction defaultAction); + + void setOpacity(qreal opacity); + void showDropAnim(); + + AppDragWidget *appDragWidget(); + +private: + AppDragWidget *m_appDragWidget; +}; + +#endif /* DRAGAPP_H */ diff --git a/frame/item/components/appdragwidget.cpp b/frame/item/components/appdragwidget.cpp new file mode 100644 index 000000000..37d0bbcd1 --- /dev/null +++ b/frame/item/components/appdragwidget.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: listenerri + * + * Maintainer: listenerri + * + * 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 3 of the License, or + * 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, see . + */ + +#include "appdragwidget.h" + +#include "../appitem.h" + +class AppGraphicsObject : public QGraphicsObject +{ +public: + AppGraphicsObject(QGraphicsItem *parent = Q_NULLPTR) : QGraphicsObject(parent) {}; + ~AppGraphicsObject() { } + + void setAppPixmap(QPixmap pix) + { + m_appPixmap = pix; + resetProperty(); + update(); + } + + void resetProperty() + { + setScale(1.0); + setRotation(0); + setOpacity(1.0); + update(); + } + + QRectF boundingRect() const Q_DECL_OVERRIDE + { + return m_appPixmap.rect(); + }; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) Q_DECL_OVERRIDE + { + Q_ASSERT(!m_appPixmap.isNull()); + + painter->drawPixmap(QPoint(0, 0), m_appPixmap); + }; + +private: + QPixmap m_appPixmap; +}; + +AppDragWidget::AppDragWidget(QWidget *parent) : + QGraphicsView(parent), + m_object(new AppGraphicsObject), + m_scene(new QGraphicsScene(this)), + m_followMouseTimer(new QTimer(this)), + m_animScale(new QPropertyAnimation(m_object, "scale", this)), + m_animRotation(new QPropertyAnimation(m_object, "rotation", this)), + m_animOpacity(new QPropertyAnimation(m_object, "opacity", this)), + m_animGroup(new QParallelAnimationGroup(this)) +{ + m_scene->addItem(m_object); + setScene(m_scene); + + setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); + setAttribute(Qt::WA_TranslucentBackground); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setMouseTracking(true); + + setAcceptDrops(true); + + initAnimations(); + + m_followMouseTimer->setSingleShot(false); + m_followMouseTimer->setInterval(1); + connect(m_followMouseTimer, &QTimer::timeout, [this] { + QPoint destPos = QCursor::pos(); + move(destPos.x() - width() / 2, destPos.y() - height() / 2); + }); + m_followMouseTimer->start(); +} + +AppDragWidget::~AppDragWidget() { } + +void AppDragWidget::dragEnterEvent(QDragEnterEvent *event) +{ + event->accept(); + + m_dragStartPoint = event->pos(); +} + +void AppDragWidget::dragMoveEvent(QDragMoveEvent *event) +{ + if (isRemoveAble()) { + m_object->setOpacity(0.5); + m_animOpacity->setStartValue(0.5); + } else { + m_object->setOpacity(1.0); + m_animOpacity->setStartValue(1.0); + } +} + +void AppDragWidget::dropEvent(QDropEvent *event) +{ + m_followMouseTimer->stop(); + + if (isRemoveAble()) { + showRemoveAnimation(); + AppItem *appItem = static_cast(event->source()); + appItem->undock(); + } else { + hide(); + } +} + +void AppDragWidget::hideEvent(QHideEvent *event) +{ + deleteLater(); +} + +void AppDragWidget::setAppPixmap(const QPixmap &pix) +{ + setFixedSize(pix.size() + QSize(10,10)); + + m_object->setAppPixmap(pix); + m_object->setTransformOriginPoint(pix.rect().center()); +} + +void AppDragWidget::setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry) +{ + m_dockPosition = dockPosition; + m_dockGeometry = dockGeometry; +} + +void AppDragWidget::initAnimations() +{ + m_animScale->setDuration(300); + m_animScale->setStartValue(1.0); + m_animScale->setEndValue(0.0); + + m_animRotation->setDuration(300); + m_animRotation->setStartValue(0); + m_animRotation->setEndValue(90); + + m_animOpacity->setDuration(300); + m_animOpacity->setStartValue(1.0); + m_animOpacity->setEndValue(0.0); + + m_animGroup->addAnimation(m_animScale); + m_animGroup->addAnimation(m_animRotation); + m_animGroup->addAnimation(m_animOpacity); + + connect(m_animGroup, &QParallelAnimationGroup::stateChanged, + this, &AppDragWidget::onRemoveAnimationStateChanged); +} + +void AppDragWidget::showRemoveAnimation() +{ + if (m_animGroup->state() == QParallelAnimationGroup::Running) { + m_animGroup->stop(); + } + m_object->resetProperty(); + m_animGroup->start(); +} + +void AppDragWidget::onRemoveAnimationStateChanged(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + if (newState == QAbstractAnimation::Stopped) { + hide(); + } +} +bool AppDragWidget::isRemoveAble() +{ + const QPoint &p = QCursor::pos(); + switch (m_dockPosition) { + case Dock::Position::Left: + if ((p.x() - m_dockGeometry.topRight().x()) > 100) { + return true; + } + break; + case Dock::Position::Top: + if ((p.y() - m_dockGeometry.bottomLeft().y()) > 100) { + return true; + } + break; + case Dock::Position::Right: + if ((m_dockGeometry.topLeft().x() - p.x()) > 100) { + return true; + } + break; + case Dock::Position::Bottom: + if ((m_dockGeometry.topLeft().y() - p.y()) > 100) { + return true; + } + break; + default: + break; + } + return false; +} diff --git a/frame/item/components/appdragwidget.h b/frame/item/components/appdragwidget.h new file mode 100644 index 000000000..84e7cf903 --- /dev/null +++ b/frame/item/components/appdragwidget.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: listenerri + * + * Maintainer: listenerri + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef APPDRAGWIDGET_H +#define APPDRAGWIDGET_H + +#include "constants.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class AppGraphicsObject; +class AppDragWidget : public QGraphicsView +{ +public: + AppDragWidget(QWidget *parent = Q_NULLPTR); + virtual ~AppDragWidget(); + + void setAppPixmap(const QPixmap &pix); + void setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry); + +protected: + void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; + void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; + void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; + +private: + void initAnimations(); + void showRemoveAnimation(); + void onRemoveAnimationStateChanged(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState); + bool isRemoveAble(); + +private: + AppGraphicsObject *m_object; + QGraphicsScene *m_scene; + QTimer *m_followMouseTimer; + QPropertyAnimation *m_animScale; + QPropertyAnimation *m_animRotation; + QPropertyAnimation *m_animOpacity; + QParallelAnimationGroup *m_animGroup; + + Dock::Position m_dockPosition; + QRect m_dockGeometry; + QPoint m_dragStartPoint; +}; + +#endif /* APPDRAGWIDGET_H */ diff --git a/frame/panel/mainpanel.cpp b/frame/panel/mainpanel.cpp index 3b23466b7..e4bcbbc15 100644 --- a/frame/panel/mainpanel.cpp +++ b/frame/panel/mainpanel.cpp @@ -4,6 +4,7 @@ * Author: sbw * * Maintainer: sbw + * listenerri * * 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 @@ -25,9 +26,11 @@ #include #include #include +#include +#include -DockItem *MainPanel::DraggingItem = nullptr; -PlaceholderItem *MainPanel::RequestDockItem = nullptr; +static DockItem *DraggingItem = nullptr; +static PlaceholderItem *RequestDockItem = nullptr; const char *RequestDockKey = "RequestDock"; @@ -36,9 +39,9 @@ MainPanel::MainPanel(QWidget *parent) m_position(Dock::Top), m_displayMode(Dock::Fashion), m_itemLayout(new QBoxLayout(QBoxLayout::LeftToRight)), - m_itemAdjustTimer(new QTimer(this)), - m_itemController(DockItemController::instance(this)) + m_itemController(DockItemController::instance(this)), + m_appDragWidget(nullptr) { m_itemLayout->setSpacing(0); m_itemLayout->setContentsMargins(0, 0, 0, 0); @@ -79,6 +82,8 @@ MainPanel::MainPanel(QWidget *parent) setLayout(m_itemLayout); } +MainPanel::~MainPanel() { } + /// /// \brief MainPanel::updateDockPosition change panel layout with spec position. /// \param dockPosition @@ -157,6 +162,23 @@ void MainPanel::setEffectEnabled(const bool enabled) m_itemAdjustTimer->start(); } +bool MainPanel::eventFilter(QObject *watched, QEvent *event) +{ + if (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; +} + void MainPanel::moveEvent(QMoveEvent* e) { DBlurEffectWidget::moveEvent(e); @@ -201,43 +223,7 @@ void MainPanel::dragEnterEvent(QDragEnterEvent *e) void MainPanel::dragMoveEvent(QDragMoveEvent *e) { - e->accept(); - - DockItem *dst = itemAt(e->pos()); - if (!dst) - return; - - // internal drag swap - if (e->source()) - { - if (dst == DraggingItem) - return; - if (!DraggingItem) - return; - if (m_itemController->itemIsInContainer(DraggingItem)) - return; - - m_itemController->itemMove(DraggingItem, dst); - } else { - DraggingItem = nullptr; - - if (!RequestDockItem) - { - DockItem *insertPositionItem = itemAt(e->pos()); - if (!insertPositionItem) - return; - const auto type = insertPositionItem->itemType(); - if (type != DockItem::App && type != DockItem::Stretch) - return; - RequestDockItem = new PlaceholderItem; - m_itemController->placeholderItemAdded(RequestDockItem, insertPositionItem); - } else { - if (dst == RequestDockItem) - return; - - m_itemController->itemMove(RequestDockItem, dst); - } - } + handleDragMove(e, false); } void MainPanel::dragLeaveEvent(QDragLeaveEvent *e) @@ -539,6 +525,14 @@ void MainPanel::itemDragStarted() { DraggingItem = qobject_cast(sender()); + if (DraggingItem->itemType() == DockItem::App) + { + AppItem *appItem = qobject_cast(DraggingItem); + m_appDragWidget = appItem->appDragWidget(); + appItem->setDockInfo(m_position, QRect(mapToGlobal(pos()), size())); + static_cast(m_appDragWidget)->viewport()->installEventFilter(this); + } + if (DraggingItem->itemType() == DockItem::Plugins) { if (static_cast(DraggingItem)->allowContainer()) @@ -563,12 +557,12 @@ void MainPanel::itemDropped(QObject *destnation) { m_itemController->setDropping(false); - if (m_displayMode == Dock::Fashion) - return; - DockItem *src = qobject_cast(sender()); // DockItem *dst = qobject_cast(destnation); + if (m_displayMode == Dock::Fashion) + return; + if (!src) return; @@ -584,3 +578,45 @@ void MainPanel::itemDropped(QObject *destnation) m_itemAdjustTimer->start(); } + +void MainPanel::handleDragMove(QDragMoveEvent *e, bool isFilter) +{ + e->accept(); + + DockItem *dst = itemAt(isFilter ? mapFromGlobal(m_appDragWidget->mapToGlobal(e->pos())) : e->pos()); + + if (!dst) + return; + + // internal drag swap + if (e->source()) + { + if (dst == DraggingItem) + return; + if (!DraggingItem) + return; + if (m_itemController->itemIsInContainer(DraggingItem)) + return; + + m_itemController->itemMove(DraggingItem, dst); + } else { + DraggingItem = nullptr; + + if (!RequestDockItem) + { + DockItem *insertPositionItem = itemAt(e->pos()); + if (!insertPositionItem) + return; + const auto type = insertPositionItem->itemType(); + if (type != DockItem::App && type != DockItem::Stretch) + return; + RequestDockItem = new PlaceholderItem; + m_itemController->placeholderItemAdded(RequestDockItem, insertPositionItem); + } else { + if (dst == RequestDockItem) + return; + + m_itemController->itemMove(RequestDockItem, dst); + } + } +} diff --git a/frame/panel/mainpanel.h b/frame/panel/mainpanel.h index 1b9017d3e..7b9102a02 100644 --- a/frame/panel/mainpanel.h +++ b/frame/panel/mainpanel.h @@ -4,6 +4,7 @@ * Author: sbw * * Maintainer: sbw + * listenerri * * 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 @@ -49,6 +50,7 @@ class MainPanel : public DBlurEffectWidget public: explicit MainPanel(QWidget *parent = 0); + virtual ~MainPanel(); void updateDockPosition(const Position dockPosition); void updateDockDisplayMode(const Dock::DisplayMode displayMode); @@ -57,6 +59,8 @@ public: void setEffectEnabled(const bool enabled); + bool eventFilter(QObject *watched, QEvent *event); + signals: void requestWindowAutoHide(const bool autoHide) const; void requestRefershWindowVisible() const; @@ -80,6 +84,7 @@ private slots: void itemMoved(DockItem *item, const int index); void itemDragStarted(); void itemDropped(QObject *destnation); + void handleDragMove(QDragMoveEvent *e, bool isFilter); private: Position m_position; @@ -89,8 +94,7 @@ private: QTimer *m_itemAdjustTimer; DockItemController *m_itemController; - static DockItem *DraggingItem; - static PlaceholderItem *RequestDockItem; + QWidget *m_appDragWidget; }; #endif // MAINPANEL_H