add: drag drop app item animation

Change-Id: I9ca4f97ac4a1227bef0f9cd856ac52b66de4465d
This commit is contained in:
listenerri 2018-06-04 21:09:41 +08:00
parent 34b5a7bcf1
commit 88fceb9589
Notes: gerrit 2018-07-23 17:24:51 +08:00
Verified+1: <jenkins@deepin.com>
Code-Review+2: hualet <mr.asianwang@gmail.com>
Submitted-by: listenerri <listenerri@gmail.com>
Submitted-at: Mon, 23 Jul 2018 17:24:50 +0800
Reviewed-on: https://cr.deepin.io/35399
Project: dde/dde-dock
Branch: refs/heads/master
8 changed files with 539 additions and 56 deletions

View File

@ -4,6 +4,7 @@
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* listenerri <listenerri@gmail.com>
*
* 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<AppDrag *>(m_drag)->appDragWidget();
}
void AppItem::setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry)
{
static_cast<AppDrag *>(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);

View File

@ -4,6 +4,7 @@
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* listenerri <listenerri@gmail.com>
*
* 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;

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: listenerri <listenerri@gmail.com>
*
* Maintainer: listenerri <listenerri@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: listenerri <listenerri@gmail.com>
*
* Maintainer: listenerri <listenerri@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef APPDRAG_H
#define APPDRAG_H
#include "appdragwidget.h"
#include <QDrag>
#include <QWidget>
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 */

View File

@ -0,0 +1,213 @@
/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: listenerri <listenerri@gmail.com>
*
* Maintainer: listenerri <listenerri@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<AppItem *>(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;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: listenerri <listenerri@gmail.com>
*
* Maintainer: listenerri <listenerri@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef APPDRAGWIDGET_H
#define APPDRAGWIDGET_H
#include "constants.h"
#include <QPixmap>
#include <QGraphicsObject>
#include <QGraphicsView>
#include <QPainter>
#include <QMouseEvent>
#include <QTimer>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <qwidget.h>
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 */

View File

@ -4,6 +4,7 @@
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* listenerri <listenerri@gmail.com>
*
* 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 <QBoxLayout>
#include <QDragEnterEvent>
#include <QApplication>
#include <QScreen>
#include <QGraphicsView>
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<QGraphicsView *>(m_appDragWidget)->viewport()) {
QDropEvent *e = static_cast<QDropEvent *>(event);
bool isContains = rect().contains(mapFromGlobal(m_appDragWidget->mapToGlobal(e->pos())));
if (isContains) {
if (event->type() == QEvent::DragMove) {
handleDragMove(static_cast<QDragMoveEvent *>(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<DockItem *>(sender());
if (DraggingItem->itemType() == DockItem::App)
{
AppItem *appItem = qobject_cast<AppItem *>(DraggingItem);
m_appDragWidget = appItem->appDragWidget();
appItem->setDockInfo(m_position, QRect(mapToGlobal(pos()), size()));
static_cast<QGraphicsView *>(m_appDragWidget)->viewport()->installEventFilter(this);
}
if (DraggingItem->itemType() == DockItem::Plugins)
{
if (static_cast<PluginsItem *>(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<DockItem *>(sender());
// DockItem *dst = qobject_cast<DockItem *>(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);
}
}
}

View File

@ -4,6 +4,7 @@
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* listenerri <listenerri@gmail.com>
*
* 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