dde-dock/frame/item/components/appdragwidget.cpp
duanhongyu 72b1b37c35 fix: 修改wayland处理任务栏拖拽的逻辑
之前处理wayland逻辑存在不同, 修改部分逻辑保持显示一致

Log: 鼠标把应用图标拖拽出任务栏的效果显示有误
Bug: https://pms.uniontech.com/zentao/bug-view-100046.html
Influence: 任务栏-拖拽逻辑
Change-Id: I73c06291d69bf1c1e9c9ab7a4924d5fcfffd33ea
2021-12-17 13:22:22 +08:00

435 lines
13 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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 "../appitem.h"
#include "appdragwidget.h"
#include "utils.h"
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.get(), "scale", this))
, m_animRotation(new QPropertyAnimation(m_object.get(), "rotation", this))
, m_animOpacity(new QPropertyAnimation(m_object.get(), "opacity", this))
, m_animGroup(new QParallelAnimationGroup(this))
, m_goBackAnim(new QPropertyAnimation(this, "pos", this))
, m_dockPosition(Dock::Position::Bottom)
, m_removeTips(new TipsWidget(this))
, m_popupWindow(new DockPopupWindow(nullptr))
, m_distanceMultiple(Utils::SettingValue("com.deepin.dde.dock.distancemultiple", "/com/deepin/dde/dock/distancemultiple/", "distance-multiple", 1.5).toDouble())
, m_item(nullptr)
{
m_removeTips->setText(tr("Remove"));
m_removeTips->setObjectName("AppRemoveTips");
m_removeTips->setVisible(false);
m_removeTips->installEventFilter(this);
m_popupWindow->setShadowBlurRadius(20);
m_popupWindow->setRadius(18);
m_popupWindow->setShadowYOffset(2);
m_popupWindow->setShadowXOffset(0);
m_popupWindow->setArrowWidth(18);
m_popupWindow->setArrowHeight(10);
m_popupWindow->setRadius(18);
m_scene->addItem(m_object.get());
setScene(m_scene);
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
setAttribute(Qt::WA_TranslucentBackground);
if (Utils::IS_WAYLAND_DISPLAY) {
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::Window);
setAttribute(Qt::WA_NativeWindow);
}
viewport()->setAutoFillBackground(false);
setFrameShape(QFrame::NoFrame);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setMouseTracking(true);
setAcceptDrops(true);
initAnimations();
m_followMouseTimer->setInterval(16);
connect(m_followMouseTimer, &QTimer::timeout, this, &AppDragWidget::onFollowMouse);
m_followMouseTimer->start();
}
void AppDragWidget::mouseMoveEvent(QMouseEvent *event)
{
QGraphicsView::mouseMoveEvent(event);
// hide widget when receiving mouseMoveEvent because this means drag-and-drop has been finished
if (m_goBackAnim->state() != QPropertyAnimation::State::Running
&& m_animGroup->state() != QParallelAnimationGroup::Running) {
hide();
}
}
void AppDragWidget::dragEnterEvent(QDragEnterEvent *event)
{
event->accept();
m_bDragDrop = true;
}
void AppDragWidget::dragMoveEvent(QDragMoveEvent *event)
{
Q_UNUSED(event);
showRemoveTips();
if (isRemoveItem() && m_bDragDrop) {
emit requestRemoveItem();
}
}
/**获取应用的左上角坐标
* @brief AppDragWidget::topleftPoint
* @return 返回应用左上角坐标
*/
const QPoint AppDragWidget::topleftPoint() const
{
QPoint p;
const QWidget *w = this;
do {
p += w->pos();
w = qobject_cast<QWidget *>(w->parent());
} while (w);
return p;
}
/**拖动从任务栏移除应用时浮窗坐标
* @brief AppDragWidget::popupMarkPoint
* @param pos 任务栏所在位置
* @return 拖动从任务栏移除应用时浮窗坐标
*/
const QPoint AppDragWidget::popupMarkPoint(Dock::Position pos)
{
QPoint p(topleftPoint());
QRect r = rect();
//关闭特效,原本的图标设置小,然后隐藏,需要手动设置大小保证tips位置正确
if (!DWindowManagerHelper::instance()->hasComposite()) {
r.setWidth(m_iconSize.width() + 3);
r.setHeight(m_iconSize.height() + 3);
}
switch (pos) {
case Top:
p += QPoint(r.width() / 2, r.height());
break;
case Bottom:
if (!DWindowManagerHelper::instance()->hasComposite()) {
p += QPoint(0 , -r.height() / 2);
} else {
p += QPoint(r.width() / 2, 0);
}
break;
case Left:
p += QPoint(r.width(), r.height() / 2);
break;
case Right:
p += QPoint(0, r.height() / 2);
break;
}
return p;
}
void AppDragWidget::dropEvent(QDropEvent *event)
{
m_followMouseTimer->stop();
m_bDragDrop = false;
if (isRemoveAble(QCursor::pos())) {
if (DWindowManagerHelper::instance()->hasComposite()) {
showRemoveAnimation();
} else {
hide();
}
AppItem *appItem = static_cast<AppItem *>((Utils::IS_WAYLAND_DISPLAY && m_item) ? m_item : event->source());
appItem->undock();
m_popupWindow->setVisible(false);
} else {
if (DWindowManagerHelper::instance()->hasComposite()) {
showGoBackAnimation();
} else {
hide();
}
}
}
void AppDragWidget::hideEvent(QHideEvent *event)
{
deleteLater();
if (Utils::IS_WAYLAND_DISPLAY)
QGraphicsView::hideEvent(event);
}
void AppDragWidget::setAppPixmap(const QPixmap &pix)
{
if (DWindowManagerHelper::instance()->hasComposite()) {
// QSize(3, 3) to fix pixmap be cliped
setFixedSize(pix.size() + QSize(3, 3));
} else {
setFixedSize(QSize(10, 10));
}
m_iconSize = pix.size();
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::setOriginPos(const QPoint position)
{
m_originPoint = position;
}
void AppDragWidget::setPixmapOpacity(qreal opacity)
{
if (isRemoveAble(QCursor::pos())) {
m_object->setOpacity(opacity);
m_animOpacity->setStartValue(opacity);
} else {
m_object->setOpacity(1.0);
m_animOpacity->setStartValue(1.0);
}
}
bool AppDragWidget::isRemoveable(const Position &dockPos, const QRect &doctRect)
{
const QPoint &p = QCursor::pos();
switch (dockPos) {
case Dock::Position::Left:
if ((p.x() - doctRect.topRight().x()) > (doctRect.width() * 3)) {
return true;
}
break;
case Dock::Position::Top:
if ((p.y() - doctRect.bottomLeft().y()) > (doctRect.height() * 3)) {
return true;
}
break;
case Dock::Position::Right:
if ((doctRect.topLeft().x() - p.x()) > (doctRect.width() * 3)) {
return true;
}
break;
case Dock::Position::Bottom:
if ((doctRect.topLeft().y() - p.y()) > (doctRect.height() * 3)) {
return true;
}
break;
default:
break;
}
return false;
}
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);
connect(m_goBackAnim, &QPropertyAnimation::finished, this, &AppDragWidget::hide);
}
/**显示移除动画
* @brief AppDragWidget::showRemoveAnimation
*/
void AppDragWidget::showRemoveAnimation()
{
if (m_animGroup->state() == QParallelAnimationGroup::Running) {
m_animGroup->stop();
}
m_object->resetProperty();
m_animGroup->start();
}
/**显示放弃移除后的动画
* @brief AppDragWidget::showGoBackAnimation
*/
void AppDragWidget::showGoBackAnimation()
{
m_goBackAnim->setDuration(300);
m_goBackAnim->setStartValue(pos());
m_goBackAnim->setEndValue(m_originPoint);
m_goBackAnim->start();
}
void AppDragWidget::onRemoveAnimationStateChanged(QAbstractAnimation::State newState,
QAbstractAnimation::State oldState)
{
Q_UNUSED(oldState);
if (newState == QAbstractAnimation::Stopped) {
hide();
}
}
/**判断图标拖到一定高度(默认任务栏高度的1.5倍)后是否可以移除
* @brief AppDragWidget::isRemoveAble
* @param curPos 当前鼠标所在位置
* @return 返回true可移除false不可移除
*/
bool AppDragWidget::isRemoveAble(const QPoint &curPos)
{
const QPoint &p = curPos;
switch (m_dockPosition) {
case Dock::Position::Left:
if ((p.x() - m_dockGeometry.topRight().x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
return true;
}
break;
case Dock::Position::Top:
if ((p.y() - m_dockGeometry.bottomLeft().y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
return true;
}
break;
case Dock::Position::Right:
if ((m_dockGeometry.topLeft().x() - p.x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
return true;
}
break;
case Dock::Position::Bottom:
if ((m_dockGeometry.topLeft().y() - p.y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
return true;
}
break;
}
return false;
}
/**判断应用区域图标是否被拖出任务栏
* @brief AppDragWidget::isRemoveItem
* @return 返回true应用移出任务栏false应用在任务栏内
*/
bool AppDragWidget::isRemoveItem()
{
const QPoint &p = QCursor::pos();
switch (m_dockPosition) {
case Dock::Position::Left:
if ((p.x() > m_dockGeometry.topRight().x())) {
return true;
}
break;
case Dock::Position::Top:
if ((p.y() > m_dockGeometry.bottomLeft().y())) {
return true;
}
break;
case Dock::Position::Right:
if ((m_dockGeometry.topLeft().x() > p.x())) {
return true;
}
break;
case Dock::Position::Bottom:
if ((m_dockGeometry.topLeft().y() > p.y())) {
return true;
}
break;
}
return false;
}
void AppDragWidget::onFollowMouse()
{
QPoint destPos = QCursor::pos();
if (DWindowManagerHelper::instance()->hasComposite()) {
move(destPos.x() - width() / 2, destPos.y() - height() / 2);
} else {
move(destPos.x(), destPos.y()); // 窗口特效未开启时会隐藏m_object绘制的图标移动的图标为QDrag绘制的图标
}
}
void AppDragWidget::enterEvent(QEvent *event)
{
Q_UNUSED(event);
if (m_goBackAnim->state() != QPropertyAnimation::State::Running
&& m_animGroup->state() != QParallelAnimationGroup::Running) {
hide();
}
}
/**显示移除应用提示窗口
* @brief AppDragWidget::showRemoveTips
*/
void AppDragWidget::showRemoveTips()
{
Dock::Position pos = Dock::Position::Bottom;
DockPopupWindow *popup = m_popupWindow.data();
if (isRemoveAble(QCursor::pos())) {
QWidget *lastContent = popup->getContent();
if (lastContent)
lastContent->setVisible(false);
switch (pos) {
case Top: popup->setArrowDirection(DockPopupWindow::ArrowTop); break;
case Bottom: popup->setArrowDirection(DockPopupWindow::ArrowBottom); break;
case Left: popup->setArrowDirection(DockPopupWindow::ArrowLeft); break;
case Right: popup->setArrowDirection(DockPopupWindow::ArrowRight); break;
}
popup->resize(m_removeTips->sizeHint());
popup->setContent(m_removeTips);
const QPoint p = popupMarkPoint(pos);
if (!popup->isVisible())
QMetaObject::invokeMethod(popup, "show", Qt::QueuedConnection, Q_ARG(QPoint, p), Q_ARG(bool, true));
else
popup->show(p, true);
m_object->setOpacity(0.5);
m_animOpacity->setStartValue(0.5);
} else {
m_object->setOpacity(1.0);
m_animOpacity->setStartValue(1.0);
if (popup->isVisible())
popup->setVisible(false);
}
}
void AppDragWidget::moveEvent(QMoveEvent *event)
{
Q_UNUSED(event);
showRemoveTips();
}