feat: 增加最近使用应用的功能

在MainPanelControl面板中增加一块区域,用来存放最近打开应用

Log: 增加最近使用应用功能
Influence: 控制中心最近使用区域开启情况下,时尚模式,打开一个没有驻留在任务栏的应用,查看新打开的应用是否在最近打开应用区域
Task: https://pms.uniontech.com/task-view-158441.html
Change-Id: Ibd28d16b08fcacf7ace23158725dd5dd2eae8d37
This commit is contained in:
donghualin 2022-07-08 09:05:54 +00:00
parent 0dfb004ac0
commit a4172e6763
8 changed files with 556 additions and 69 deletions

View File

@ -0,0 +1,318 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.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 "recentapphelper.h"
#include "appitem.h"
#include <QWidget>
RecentAppHelper::RecentAppHelper(QWidget *appWidget, QWidget *recentWidget, QObject *parent)
: QObject(parent)
, m_appWidget(appWidget)
, m_recentWidget(recentWidget)
{
m_appWidget->installEventFilter(this);
m_recentWidget->installEventFilter(this);
}
void RecentAppHelper::setDisplayMode(Dock::DisplayMode displayMode)
{
m_dislayMode = displayMode;
resetDockItems();
updateRecentVisible();
}
// 当在应用区域调整位置的时候,需要重新设置索引
void RecentAppHelper::resetAppInfo()
{
// 获取应用区域和最近打开区域的app图标
QList<DockItem *> appDockItem = dockItems(false);
// 获取应用区域图标在原来列表中的位置
QList<int> dockIndex;
for (DockItem *appItem : appDockItem)
dockIndex << m_sequentDockItems.indexOf(appItem);
// 按照从小到大排序
std::sort(dockIndex.begin(), dockIndex.end(), [ = ](int index1, int index2) { return index1 < index2; });
QMap<DockItem *, int> dockItemIndex;
for (int i = 0; i < appDockItem.size(); i++) {
DockItem *item = appDockItem[i];
dockItemIndex[item] = dockIndex[i];
}
// 替换原来的位置
for (DockItem *appItem : appDockItem) {
int index = -1;
if (dockItemIndex.contains(appItem))
index = dockItemIndex.value(appItem);
if (index >= 0)
m_sequentDockItems[index] = appItem;
else
m_sequentDockItems << appItem;
}
}
void RecentAppHelper::addAppItem(int index, DockItem *dockItem)
{
if (appInRecent(dockItem))
addRecentAreaItem(index, dockItem);
else
addAppAreaItem(index, dockItem);
updateRecentVisible();
connect(dockItem, &QWidget::destroyed, this, [ this, dockItem ] {
if (m_sequentDockItems.contains(dockItem))
m_sequentDockItems.removeOne(dockItem);
});
AppItem *appItem = qobject_cast<AppItem *>(dockItem);
connect(appItem, &AppItem::isDockChanged, this, &RecentAppHelper::onIsDockChanged);
// 如果索引值大于0说明它是插入到固定位置的否则则认为它是顺序排列的
if (index >= 0 && index < m_sequentDockItems.size())
m_sequentDockItems.insert(index, dockItem);
else
m_sequentDockItems << dockItem;
}
void RecentAppHelper::removeAppItem(DockItem *appItem)
{
if (appInRecent(appItem))
removeRecentAreaItem(appItem);
else
removeAppAreaItem(appItem);
}
bool RecentAppHelper::recentIsVisible() const
{
return m_recentWidget->isVisible();
}
bool RecentAppHelper::eventFilter(QObject *watched, QEvent *event)
{
if (watched == m_appWidget || watched == m_recentWidget) {
switch(event->type()) {
case QEvent::ChildAdded:
case QEvent::ChildRemoved: {
QMetaObject::invokeMethod(this, [ this ] {
/* 这里用异步的方式因为收到QEvent::ChildAdded信号的时候
Widget中QEvent::ChildRemoved信号的时候
*/
Q_EMIT requestUpdate();
}, Qt::QueuedConnection);
}
break;
default:
break;
}
}
return QObject::eventFilter(watched, event);
}
void RecentAppHelper::onIsDockChanged()
{
resetDockItems();
updateRecentVisible();
}
bool RecentAppHelper::appInRecent(DockItem *item) const
{
// 先判断当前是否为时尚模式,只有时尚模式下才支持最近打开的应用
if (m_dislayMode != Dock::DisplayMode::Fashion)
return false;
// TODO 当控制中心不开启最近打开应用的功能的时候,则始终让其显示在应用区域
// 只有当应用没有固定到任务栏上才认为它是最新打开的应用
AppItem *appItem = qobject_cast<AppItem *>(item);
return (appItem && !appItem->isDocked());
}
void RecentAppHelper::addAppAreaItem(int index, DockItem *wdg)
{
QBoxLayout *boxLayout = static_cast<QBoxLayout *>(m_appWidget->layout());
boxLayout->insertWidget(index, wdg);
}
void RecentAppHelper::addRecentAreaItem(int index, DockItem *wdg)
{
QBoxLayout *recentLayout = static_cast<QBoxLayout *>(m_recentWidget->layout());
recentLayout->insertWidget(index, wdg);
}
void RecentAppHelper::updateRecentVisible()
{
bool oldVisible = recentIsVisible();
if (m_dislayMode == Dock::DisplayMode::Efficient) {
// 如果是高效模式,不显示最近打开应用区域
m_recentWidget->setVisible(false);
} else {
QBoxLayout *recentLayout = static_cast<QBoxLayout *>(m_recentWidget->layout());
qInfo() << "recent Widget count:" << recentLayout->count();
// 如果是特效模式则判断当前打开应用数量是否为0为0则不显示否则显示
m_recentWidget->setVisible(recentLayout->count() > 0);
}
bool recentVisible = recentIsVisible();
if (oldVisible != recentVisible)
Q_EMIT recentVisibleChanged(recentVisible);
}
void RecentAppHelper::removeRecentAreaItem(DockItem *wdg)
{
QBoxLayout *recentLayout = static_cast<QBoxLayout *>(m_recentWidget->layout());
recentLayout->removeWidget(wdg);
updateRecentVisible();
}
void RecentAppHelper::removeAppAreaItem(DockItem *wdg)
{
QBoxLayout *boxLayout = static_cast<QBoxLayout *>(m_appWidget->layout());
boxLayout->removeWidget(wdg);
}
QList<DockItem *> RecentAppHelper::dockItemToAppArea() const
{
QList<DockItem *> dockItems;
if (m_dislayMode == Dock::DisplayMode::Efficient) {
// 由特效模式变成高效模式,将所有的最近打开的应用移动到左侧的应用区域
for (int i = 0; i < m_recentWidget->layout()->count(); i++) {
DockItem *appItem = qobject_cast<DockItem *>(m_recentWidget->layout()->itemAt(i)->widget());
if (!appItem)
continue;
dockItems << appItem;
}
} else {
// 如果是特效模式下,则查找所有已驻留的应用,将其移动到应用区域
for (int i = 0; i < m_recentWidget->layout()->count(); i++) {
DockItem *appItem = qobject_cast<DockItem *>(m_recentWidget->layout()->itemAt(i)->widget());
if (!appItem || appInRecent(appItem))
continue;
dockItems << appItem;
}
}
return dockItems;
}
void RecentAppHelper::resetDockItems()
{
// 先将所有的最近打开的区域移动到应用区域
QList<DockItem *> recentAppItems = dockItemToAppArea();
// 从最近使用应用中移除
for (DockItem *appItem : recentAppItems)
m_recentWidget->layout()->removeWidget(appItem);
// 将这些图标添加到应用区域
QBoxLayout *boxLayout = static_cast<QBoxLayout *>(m_appWidget->layout());
for (DockItem *appItem : recentAppItems) {
int index = getDockItemIndex(appItem, false);
if (index >= 0)
boxLayout->insertWidget(index, appItem);
else
boxLayout->addWidget(appItem);
}
if (m_dislayMode == Dock::DisplayMode::Fashion) {
// 由高效模式变成特效模式后,将左侧未驻留的应用移动到右侧的最近打开应用中
QList<DockItem *> unDockItems;
for (int i = 0; i < m_appWidget->layout()->count() ; i++) {
DockItem *appItem = qobject_cast<DockItem *>(m_appWidget->layout()->itemAt(i)->widget());
if (!appInRecent(appItem))
continue;
unDockItems << appItem;
}
// 从应用区域中删除未驻留的应用
for (DockItem *appItem : unDockItems)
m_appWidget->layout()->removeWidget(appItem);
// 将这些图标添加到最近打开区域
QBoxLayout *recentLayout = static_cast<QBoxLayout *>(m_recentWidget->layout());
for (DockItem *appItem : unDockItems) {
int index = getDockItemIndex(appItem, true);
if (index >= 0)
recentLayout->insertWidget(index, appItem);
else
recentLayout->addWidget(appItem);
}
}
}
int RecentAppHelper::getDockItemIndex(DockItem *dockItem, bool isRecent) const
{
// 当从最近区域移动到应用区域的时候,重新计算插入索引值
if (!m_sequentDockItems.contains(dockItem))
return -1;
QList<DockItem *> sequeDockItems = m_sequentDockItems;
if (isRecent) {
// 如果是最近打开区域,需要按照时间从小到大排列(先打开的排在前面)
std::sort(sequeDockItems.begin(), sequeDockItems.end(), [](DockItem *item1, DockItem *item2) {
AppItem *appItem1 = qobject_cast<AppItem *>(item1);
AppItem *appItem2 = qobject_cast<AppItem *>(item2);
if (!appItem1 || !appItem2)
return false;
return appItem1->appOpenMSecs() < appItem2->appOpenMSecs();
});
}
int index = sequeDockItems.indexOf(dockItem);
// 查找所有在应用区域的图标
QList<DockItem *> dockApps = dockItems(isRecent);
for (int i = index + 1; i < sequeDockItems.size(); i++) {
DockItem *item = sequeDockItems[i];
if (dockApps.contains(item))
return dockApps.indexOf(item);
}
return -1;
}
QList<DockItem *> RecentAppHelper::dockItems(bool isRecent) const
{
QLayout *layout = nullptr;
if (isRecent)
layout = m_recentWidget->layout();
else
layout = m_appWidget->layout();
QList<DockItem *> dockItems;
for (int i = 0; i < layout->count(); i++) {
DockItem *dockItem = qobject_cast<DockItem *>(layout->itemAt(i)->widget());
if (!dockItem)
continue;
dockItems << dockItem;
}
return dockItems;
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.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 RECENTAPPHELPER_H
#define RECENTAPPHELPER_H
#include "constants.h"
#include <QObject>
class DockItem;
class QWidget;
/** 用来管理最近打开区域和APP应用区域交互的类
* @brief The RecentAppManager class
*/
class RecentAppHelper : public QObject
{
Q_OBJECT
public:
explicit RecentAppHelper(QWidget *appWidget, QWidget *recentWidget, QObject *parent = nullptr);
void setDisplayMode(Dock::DisplayMode displayMode);
void resetAppInfo();
void addAppItem(int index, DockItem *appItem);
void removeAppItem(DockItem *appItem);
bool recentIsVisible() const;
Q_SIGNALS:
void requestUpdate();
void recentVisibleChanged(bool); // 最近区域是否可见发生变化的信号
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
bool appInRecent(DockItem *item) const;
void addAppAreaItem(int index, DockItem *wdg);
void addRecentAreaItem(int index, DockItem *wdg);
void updateRecentVisible();
void removeRecentAreaItem(DockItem *wdg);
void removeAppAreaItem(DockItem *wdg);
QList<DockItem *> dockItemToAppArea() const;
void resetDockItems();
int getDockItemIndex(DockItem *dockItem, bool isRecent) const;
QList<DockItem *> dockItems(bool isRecent) const;
private Q_SLOTS:
void onIsDockChanged();
private:
QWidget *m_appWidget;
QWidget *m_recentWidget;
QList<DockItem *> m_sequentDockItems;
Dock::DisplayMode m_dislayMode;
};
#endif // RECENTAPPHELPER_H

View File

@ -69,6 +69,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti
, m_retryObtainIconTimer(new QTimer(this))
, m_refershIconTimer(new QTimer(this))
, m_themeType(DGuiApplicationHelper::instance()->themeType())
, m_createMSecs(QDateTime::currentMSecsSinceEpoch())
{
QHBoxLayout *centralLayout = new QHBoxLayout;
centralLayout->setMargin(0);
@ -94,6 +95,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti
connect(m_itemEntryInter, &DockEntryInter::IsActiveChanged, this, static_cast<void (AppItem::*)()>(&AppItem::update));
connect(m_itemEntryInter, &DockEntryInter::WindowInfosChanged, this, &AppItem::updateWindowInfos, Qt::QueuedConnection);
connect(m_itemEntryInter, &DockEntryInter::IconChanged, this, &AppItem::refreshIcon);
connect(m_itemEntryInter, &DockEntryInter::IsDockedChanged, this, &AppItem::isDockChanged);
connect(m_updateIconGeometryTimer, &QTimer::timeout, this, &AppItem::updateWindowIconGeometries, Qt::QueuedConnection);
connect(m_retryObtainIconTimer, &QTimer::timeout, this, &AppItem::refreshIcon, Qt::QueuedConnection);
@ -185,6 +187,21 @@ QString AppItem::accessibleName()
return m_itemEntryInter->name();
}
void AppItem::requestDock()
{
m_itemEntryInter->RequestDock();
}
bool AppItem::isDocked() const
{
return m_itemEntryInter->isDocked();
}
qint64 AppItem::appOpenMSecs() const
{
return m_createMSecs;
}
void AppItem::moveEvent(QMoveEvent *e)
{
DockItem::moveEvent(e);
@ -564,6 +581,10 @@ QPoint AppItem::appIconPosition() const
void AppItem::updateWindowInfos(const WindowInfoMap &info)
{
// 如果是打开第一个窗口,则更新窗口时间
if (m_windowInfos.isEmpty() && !info.isEmpty())
m_createMSecs = QDateTime::currentMSecsSinceEpoch();
m_windowInfos = info;
if (m_appPreviewTips)
m_appPreviewTips->setWindowInfos(m_windowInfos, m_itemEntryInter->GetAllowedCloseWindows().value());

View File

@ -56,6 +56,9 @@ public:
inline ItemType itemType() const override { return App; }
QPixmap appIcon(){ return m_appIcon; }
virtual QString accessibleName() override;
void requestDock();
bool isDocked() const;
qint64 appOpenMSecs() const;
signals:
void requestActivateWindow(const WId wid) const;
@ -64,6 +67,7 @@ signals:
void dragReady(QWidget *dragWidget);
void requestUpdateEntryGeometries() const;
void isDockChanged(bool) const;
private:
void moveEvent(QMoveEvent *e) override;
@ -139,6 +143,7 @@ private:
QDate m_curDate; // 保存当前icon的日期来判断是否需要更新日历APP的ICON
DGuiApplicationHelper::ColorType m_themeType;
qint64 m_createMSecs;
static QPoint MousePressPos;
};

View File

@ -41,13 +41,14 @@ class DockItem : public QWidget
public:
enum ItemType {
Launcher,
App,
Plugins,
FixedPlugin,
Launcher, // 启动器
App, // 任务栏区域的应用
Plugins, // 插件区域图标
FixedPlugin, // 固定区域图标,例如多任务试图
Placeholder,
TrayPlugin,
QuickSettingPlugin
TrayPlugin, // 托盘插件
QuickSettingPlugin, // 快捷设置区域插件
StretchPlugin // 时尚模式下的固定在最右侧的插件,例如开关机插件
};
public:
@ -57,7 +58,7 @@ public:
static void setDockPosition(const Position side);
static void setDockDisplayMode(const DisplayMode mode);
inline virtual ItemType itemType() const {return App;}
inline virtual ItemType itemType() const = 0;
QSize sizeHint() const override;
virtual QString accessibleName();

View File

@ -34,6 +34,7 @@
#include "traymanagerwindow.h"
#include "multiscreenworker.h"
#include "displaymanager.h"
#include "recentapphelper.h"
#include <QDrag>
#include <QTimer>
@ -84,16 +85,19 @@ MainPanelControl::MainPanelControl(QWidget *parent)
, m_trayAreaLayout(new QBoxLayout(QBoxLayout::LeftToRight, this))
, m_traySpliter(new QLabel(this))
, m_pluginAreaWidget(new QWidget(this))
, m_recentAreaWidget(new QWidget(this))
, m_recentLayout(new QBoxLayout(QBoxLayout::LeftToRight, this))
, m_trayManagerWidget(new TrayManagerWindow(this))
, m_pluginLayout(new QBoxLayout(QBoxLayout::LeftToRight, this))
, m_desktopWidget(new DesktopWidget(this))
, m_position(Position::Bottom)
, m_placeholderItem(nullptr)
, m_appDragWidget(nullptr)
, m_dislayMode(Efficient)
, m_displayMode(Efficient)
, m_tray(nullptr)
, m_trashItem(nullptr)
, m_dockScreen(nullptr)
, m_recentHelper(new RecentAppHelper(m_appAreaSonWidget, m_recentAreaWidget, this))
{
initUI();
initConnection();
@ -107,11 +111,11 @@ MainPanelControl::MainPanelControl(QWidget *parent)
m_trayAreaWidget->installEventFilter(this);
m_pluginAreaWidget->installEventFilter(this);
//在设置每条线大小前应该设置fixedsize(0,0)
//应为paintEvent函数会先调用设置背景颜色大小为随机值
m_fixedSpliter->setFixedSize(0,0);
m_appSpliter ->setFixedSize(0,0);
m_traySpliter->setFixedSize(0,0);
// 在设置每条线大小前应该设置fixedsize(0,0)
// 应为paintEvent函数会先调用设置背景颜色大小为随机值
m_fixedSpliter->setFixedSize(0, 0);
m_appSpliter ->setFixedSize(0, 0);
m_traySpliter->setFixedSize(0, 0);
}
void MainPanelControl::initUI()
@ -137,6 +141,14 @@ void MainPanelControl::initUI()
m_appSpliter->setObjectName("spliter_app");
m_mainPanelLayout->addWidget(m_appSpliter);
/* 最近打开应用 */
m_recentAreaWidget->setObjectName("recentarea");
m_recentAreaWidget->setAccessibleName("recentarea");
m_recentAreaWidget->setLayout(m_recentLayout);
m_recentLayout->setSpacing(0);
m_recentLayout->setContentsMargins(0, 0, 0, 0);
m_mainPanelLayout->addWidget(m_recentAreaWidget);
/* 托盘区域 */
m_trayAreaWidget->setObjectName("trayarea");
m_trayAreaWidget->setLayout(m_trayAreaLayout);
@ -154,6 +166,7 @@ void MainPanelControl::initUI()
m_pluginLayout->setContentsMargins(0, 0, 0, 0);
m_mainPanelLayout->addWidget(m_pluginAreaWidget, 0, Qt::AlignCenter);
/* 时尚模式下右侧的插件区域 */
m_mainPanelLayout->addSpacing(15);
m_mainPanelLayout->addWidget(m_trayManagerWidget);
@ -171,6 +184,8 @@ void MainPanelControl::initUI()
void MainPanelControl::initConnection()
{
connect(m_trayManagerWidget, &TrayManagerWindow::requestUpdate, this, &MainPanelControl::onRequestUpdate);
connect(m_recentHelper, &RecentAppHelper::requestUpdate, this, &MainPanelControl::requestUpdate);
connect(m_recentHelper, &RecentAppHelper::recentVisibleChanged, this, &MainPanelControl::onRecentVisibleChanged);
}
/**
@ -179,10 +194,11 @@ void MainPanelControl::initConnection()
*/
void MainPanelControl::setDisplayMode(DisplayMode dislayMode)
{
if (dislayMode == m_dislayMode)
if (dislayMode == m_displayMode)
return;
m_dislayMode = dislayMode;
m_displayMode = dislayMode;
m_recentHelper->setDisplayMode(dislayMode);
updateDisplayMode();
}
@ -204,6 +220,7 @@ void MainPanelControl::updateMainPanelLayout()
m_pluginLayout->setDirection(QBoxLayout::LeftToRight);
m_trayAreaLayout->setDirection(QBoxLayout::LeftToRight);
m_appAreaSonLayout->setDirection(QBoxLayout::LeftToRight);
m_recentLayout->setDirection(QBoxLayout::LeftToRight);
m_trayAreaLayout->setContentsMargins(0, 10, 0, 10);
m_pluginLayout->setContentsMargins(10, 0, 10, 0);
break;
@ -219,6 +236,7 @@ void MainPanelControl::updateMainPanelLayout()
m_pluginLayout->setDirection(QBoxLayout::TopToBottom);
m_trayAreaLayout->setDirection(QBoxLayout::TopToBottom);
m_appAreaSonLayout->setDirection(QBoxLayout::TopToBottom);
m_recentLayout->setDirection(QBoxLayout::TopToBottom);
m_trayAreaLayout->setContentsMargins(10, 0, 10, 0);
m_pluginLayout->setContentsMargins(0, 10, 0, 10);
break;
@ -247,22 +265,6 @@ void MainPanelControl::addFixedAreaItem(int index, QWidget *wdg)
Q_EMIT requestUpdate();
}
/**往应用区域添加应用
* @brief MainPanelControl::addAppAreaItem
* @param index 
* @param wdg 
*/
void MainPanelControl::addAppAreaItem(int index, QWidget *wdg)
{
if(m_position == Position::Top || m_position == Position::Bottom){
wdg->setMaximumSize(height(),height());
} else {
wdg->setMaximumSize(width(),width());
}
m_appAreaSonLayout->insertWidget(index, wdg);
Q_EMIT requestUpdate();
}
/**往托盘插件区域添加应用
* @brief MainPanelControl::addTrayAreaItem
* @param index 
@ -330,8 +332,8 @@ void MainPanelControl::removeTrayAreaItem(QWidget *wdg)
*/
void MainPanelControl::removePluginAreaItem(QWidget *wdg)
{
//因为日期时间插件大小和其他插件有异,为了方便设置边距,各插件中增加一层布局
//因此remove插件图标时需要从多的一层布局中取widget进行判断是否需要移除的插件
// 因为日期时间插件大小和其他插件有异,为了方便设置边距,各插件中增加一层布局
// 因此remove插件图标时需要从多的一层布局中取widget进行判断是否需要移除的插件
// 清空保存的垃圾箱插件指针
PluginsItem *pluginsItem = qobject_cast<PluginsItem *>(wdg);
if (pluginsItem && pluginsItem->pluginName() == "trash")
@ -351,9 +353,9 @@ void MainPanelControl::removePluginAreaItem(QWidget *wdg)
void MainPanelControl::resizeEvent(QResizeEvent *event)
{
//先通过消息循环让各部件调整好size后再计算图标大小
//避免因为部件size没有调整完导致计算的图标大小不准确
//然后重复触发m_pluginAreaWidget的reszie事件并重复计算造成任务栏图标抖动问题
// 先通过消息循环让各部件调整好size后再计算图标大小
// 避免因为部件size没有调整完导致计算的图标大小不准确
// 然后重复触发m_pluginAreaWidget的reszie事件并重复计算造成任务栏图标抖动问题
QWidget::resizeEvent(event);
resizeDesktopWidget();
resizeDockIcon();
@ -367,21 +369,43 @@ void MainPanelControl::resetRadius()
qApp->setProperty("EffectBorderRadius", radius);
}
/** 当用户从最近使用区域拖动应用到左侧应用区域的时候,将该应用驻留
* @brief MainPanelControl::dockRecentApp
* @param dockItem
*/
void MainPanelControl::dockRecentApp(DockItem *dockItem)
{
// 如果当前不是特效模式,则无需做驻留操作
if (m_displayMode != Dock::DisplayMode::Fashion)
return;
AppItem *appItem = qobject_cast<AppItem *>(dockItem);
if (!appItem)
return;
// TODO 如果控制中心设置不开启最近应用,则不让其驻留
// 如果控制中心开启了最近应用并且当前应用是未驻留应用,则可以驻留
if (!appItem->isDocked())
appItem->requestDock();
}
/**根据任务栏所在位置, 设置应用区域控件的大小
* @brief MainPanelControl::updateAppAreaSonWidgetSize
*/
void MainPanelControl::updateAppAreaSonWidgetSize()
{
if ((m_position == Position::Top) || (m_position == Position::Bottom)) {
m_appAreaSonWidget->setMaximumHeight(this->height());
m_appAreaSonWidget->setMaximumHeight(height());
m_appAreaSonWidget->setMaximumWidth(m_appAreaWidget->width());
m_recentAreaWidget->setFixedHeight(height());
} else {
m_appAreaSonWidget->setMaximumWidth(this->width());
m_appAreaSonWidget->setMaximumWidth(width());
m_appAreaSonWidget->setMaximumHeight(m_appAreaWidget->height());
m_recentAreaWidget->setFixedWidth(width());
}
m_appAreaSonWidget->adjustSize();
moveAppSonWidget();
}
@ -422,7 +446,7 @@ void MainPanelControl::insertItem(int index, DockItem *item)
break;
case DockItem::App:
case DockItem::Placeholder:
addAppAreaItem(index, item);
m_recentHelper->addAppItem(index, item);
break;
case DockItem::TrayPlugin: // 此处只会有一个tray系统托盘插件微信、声音、网络蓝牙等等都在系统托盘插件中处理的
addTrayAreaItem(index, item);
@ -454,7 +478,7 @@ void MainPanelControl::removeItem(DockItem *item)
break;
case DockItem::App:
case DockItem::Placeholder:
removeAppAreaItem(item);
m_recentHelper->removeAppItem(item);
break;
case DockItem::TrayPlugin:
removeTrayAreaItem(item);
@ -538,6 +562,7 @@ void MainPanelControl::dragLeaveEvent(QDragLeaveEvent *e)
removeAppAreaItem(m_placeholderItem);
m_placeholderItem->deleteLater();
m_placeholderItem = nullptr;
}
}
@ -675,7 +700,7 @@ bool MainPanelControl::eventFilter(QObject *watched, QEvent *event)
// NormalContainer部件尺寸变化完成之前就已经结束导致
// NormalContainer没有更新自己的尺寸引起插件区域拥挤
if (m_tray && watched == m_tray && event->type() == QEvent::Resize)
m_tray->pluginItem()->displayModeChanged(m_dislayMode);
m_tray->pluginItem()->displayModeChanged(m_displayMode);
// 更新应用区域大小和任务栏图标大小
if (watched == m_appAreaSonWidget) {
@ -793,12 +818,17 @@ void MainPanelControl::startDrag(DockItem *dockItem)
connect(m_appDragWidget, &AppDragWidget::destroyed, this, [ = ] {
m_appDragWidget = nullptr;
if (!item.isNull() && qobject_cast<AppItem *>(item)->isValid()) {
// 如果是从最近打开区域移动到应用区域的,则需要将其固定
dockRecentApp(item);
if (-1 == m_appAreaSonLayout->indexOf(item) && m_dragIndex != -1) {
insertItem(m_dragIndex, item);
m_dragIndex = -1;
}
item->setDraging(false);
item->update();
// 发送拖拽完成事件
m_recentHelper->resetAppInfo();
}
});
@ -921,13 +951,12 @@ void MainPanelControl::updateDisplayMode()
void MainPanelControl::updateModeChange()
{
m_trayAreaWidget->setVisible(m_dislayMode == DisplayMode::Efficient);
m_traySpliter->setVisible(m_dislayMode == DisplayMode::Efficient);
m_appSpliter->setVisible(m_dislayMode == DisplayMode::Efficient);
m_pluginAreaWidget->setVisible(m_dislayMode == DisplayMode::Efficient);
m_trayManagerWidget->setVisible(m_dislayMode != DisplayMode::Efficient);
m_trayAreaWidget->setVisible(m_displayMode == DisplayMode::Efficient);
m_traySpliter->setVisible(m_displayMode == DisplayMode::Efficient);
m_pluginAreaWidget->setVisible(m_displayMode == DisplayMode::Efficient);
m_trayManagerWidget->setVisible(m_displayMode != DisplayMode::Efficient);
if (m_tray)
m_tray->setVisible(m_dislayMode == DisplayMode::Efficient);
m_tray->setVisible(m_displayMode == DisplayMode::Efficient);
}
/**把驻留应用和被打开的应用所在窗口移动到指定位置
@ -936,7 +965,7 @@ void MainPanelControl::updateModeChange()
void MainPanelControl::moveAppSonWidget()
{
QRect rect(QPoint(0, 0), m_appAreaSonWidget->size());
if (DisplayMode::Efficient == m_dislayMode) {
if (DisplayMode::Efficient == m_displayMode) {
switch (m_position) {
case Top:
case Bottom :
@ -999,22 +1028,29 @@ void MainPanelControl::setDockScreen(DockScreen *dockScreen)
QPainterPath MainPanelControl::areaPath()
{
if (m_dislayMode == DisplayMode::Efficient)
if (m_displayMode == DisplayMode::Efficient)
return QPainterPath();
int radius = qApp->property("EffectBorderRadius").toInt();
QPainterPath path;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
int leftWidth = m_fixedAreaWidget->width() + m_fixedSpliter->width() + m_appAreaWidget->width();
if (m_recentLayout->count() > 0)
leftWidth += m_recentAreaWidget->width();
int roundHeight = height();
path.addRoundedRect(QRect(0, 0, leftWidth, roundHeight), radius, radius);
path.addRoundedRect(QRect(m_trayManagerWidget->x(), 0, m_trayManagerWidget->width(), roundHeight), radius, radius);
} else {
int roundWidth = width();
int topHeight = m_fixedAreaWidget->height() + m_fixedSpliter->height() + m_appAreaWidget->height();
if (m_recentLayout->count() > 0)
topHeight += m_recentAreaWidget->height();
path.addRoundedRect(QRect(0, 0, roundWidth, topHeight), radius, radius);
path.addRoundedRect(QRect(0, m_trayManagerWidget->y(), roundWidth, m_trayManagerWidget->height()), radius, radius);
}
return path;
}
@ -1027,7 +1063,7 @@ QSize MainPanelControl::suitableSize(int screenSize, double deviceRatio) const
if (ratio <= 0)
ratio = qApp->devicePixelRatio();
if (m_dislayMode == DisplayMode::Efficient) {
if (m_displayMode == DisplayMode::Efficient) {
// 如果是高效模式
if (m_position == Position::Top || m_position == Position::Bottom)
return QSize(static_cast<int>(screenSize / ratio), height());
@ -1041,7 +1077,7 @@ QSize MainPanelControl::suitableSize(int screenSize, double deviceRatio) const
// 减去右侧托盘和快捷设置还有插件区域的尺寸
totalLength -= (((m_position == Position::Top || m_position == Position::Bottom) ? traySuitableSize.width() : traySuitableSize.height()) / ratio);
// 需要参与计算的图标的总数
int iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count();
int iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count();
if (iconCount <= 0) {
if (m_position == Position::Top || m_position == Position::Bottom)
return QSize((static_cast<int>((traySuitableSize.width() + 20) / ratio)), height());
@ -1126,13 +1162,14 @@ void MainPanelControl::resizeDockIcon()
int tray_item_size = 0;
int iconCount = 0;
// 总宽度
if (m_dislayMode == DisplayMode::Fashion) {
if (m_displayMode == DisplayMode::Fashion) {
// 时尚模式
int totalLength = getScreenSize();
QSize trayManagerSize = m_trayManagerWidget->suitableSize();
// 减去右侧托盘和插件区域的宽度
totalLength -= ((m_position == Position::Top) || (m_position == Position::Bottom)) ? trayManagerSize.width() : trayManagerSize.height();
iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count();
iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count();
if (iconCount <= 0)
return;
@ -1255,9 +1292,8 @@ void MainPanelControl::calcuDockIconSize(int w, int h, int traySize)
{
int appItemSize = qMin(w, h);
for (int i = 0; i < m_fixedAreaLayout->count(); ++i) {
for (int i = 0; i < m_fixedAreaLayout->count(); ++i)
m_fixedAreaLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize);
}
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
m_fixedSpliter->setFixedSize(SPLITER_SIZE, int(w * 0.6));
@ -1269,16 +1305,26 @@ void MainPanelControl::calcuDockIconSize(int w, int h, int traySize)
m_traySpliter->setFixedSize(int(h * 0.5), SPLITER_SIZE);
}
for (int i = 0; i < m_appAreaSonLayout->count(); ++i) {
for (int i = 0; i < m_appAreaSonLayout->count(); ++i)
m_appAreaSonLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize);
// 时尚模式下判断是否需要显示最近打开的应用区域
if (m_displayMode == Dock::DisplayMode::Fashion && m_recentLayout->count() > 0) {
for (int i = 0; i < m_recentLayout->count(); ++i)
m_recentLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize);
// 时尚模式下计算最近打开应用区域的尺寸
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
m_recentAreaWidget->setFixedWidth(appItemSize * m_recentLayout->count());
else
m_recentAreaWidget->setFixedHeight(appItemSize * m_recentLayout->count());
}
if (m_tray) {
if (m_tray)
m_tray->centralWidget()->setProperty("iconSize", traySize);
}
//因为日期时间大小和其他插件大小有异,为了设置边距,在各插件中增加了一层布局
//因此需要通过多一层布局来获取各插件
// 因为日期时间大小和其他插件大小有异,为了设置边距,在各插件中增加了一层布局
// 因此需要通过多一层布局来获取各插件
if ((m_position == Position::Top) || (m_position == Position::Bottom)) {
// 三方插件
for (int i = 0; i < m_pluginLayout->count(); ++ i) {
@ -1352,6 +1398,11 @@ void MainPanelControl::onRequestUpdate()
Q_EMIT requestUpdate();
}
void MainPanelControl::onRecentVisibleChanged(bool visible)
{
m_appSpliter->setVisible(visible);
}
/**时尚模式没有‘显示桌面’区域
* @brief MainPanelControl::resizeDesktopWidget
*/
@ -1375,7 +1426,7 @@ void MainPanelControl::resizeDesktopWidget()
m_trayManagerWidget->setFixedWidth(suitableSize.width());
}
if (DisplayMode::Fashion == m_dislayMode)
if (DisplayMode::Fashion == m_displayMode)
m_desktopWidget->setFixedSize(0, 0);
}

View File

@ -40,10 +40,12 @@ class AppDragWidget;
class DesktopWidget;
class TrayManagerWindow;
class DockScreen;
class RecentAppHelper;
class MainPanelControl : public QWidget
{
Q_OBJECT
public:
explicit MainPanelControl(QWidget *parent = nullptr);
@ -77,7 +79,6 @@ private:
void addFixedAreaItem(int index, QWidget *wdg);
void removeFixedAreaItem(QWidget *wdg);
void addAppAreaItem(int index, QWidget *wdg);
void removeAppAreaItem(QWidget *wdg);
void addTrayAreaItem(int index, QWidget *wdg);
void removeTrayAreaItem(QWidget *wdg);
@ -95,9 +96,11 @@ private:
bool checkNeedShowDesktop();
bool appIsOnDock(const QString &appDesktop);
void resetRadius();
void dockRecentApp(DockItem *dockItem);
private Q_SLOTS:
void onRequestUpdate();
void onRecentVisibleChanged(bool visible);
protected:
void dragMoveEvent(QDragMoveEvent *e) override;
@ -114,31 +117,35 @@ private:
QBoxLayout *m_mainPanelLayout;
QWidget *m_fixedAreaWidget; // 固定区域
QBoxLayout *m_fixedAreaLayout; //
QBoxLayout *m_fixedAreaLayout; // 固定区域布局
QLabel *m_fixedSpliter; // 固定区域与应用区域间的分割线
QWidget *m_appAreaWidget; // 应用区域
QWidget *m_appAreaSonWidget; // 子应用区域,所在位置根据显示模式手动指定
QBoxLayout *m_appAreaSonLayout; //
QBoxLayout *m_appAreaSonLayout; // 子应用区域布局
QLabel *m_appSpliter; // 应用区域与托盘区域间的分割线
QWidget *m_trayAreaWidget; // 托盘区域
QBoxLayout *m_trayAreaLayout; //
QBoxLayout *m_trayAreaLayout; // 托盘区域布局
QLabel *m_traySpliter; // 托盘区域与插件区域间的分割线
QWidget *m_pluginAreaWidget; // 插件区域
QWidget *m_recentAreaWidget; // 最近打开应用
QBoxLayout *m_recentLayout;
TrayManagerWindow *m_trayManagerWidget;
QBoxLayout *m_pluginLayout; //
QBoxLayout *m_pluginLayout; // 插件区域布局
DesktopWidget *m_desktopWidget; // 桌面预览区域
Position m_position;
QPointer<PlaceholderItem> m_placeholderItem;
QString m_draggingMimeKey;
AppDragWidget *m_appDragWidget;
DisplayMode m_dislayMode;
DisplayMode m_displayMode;
QPoint m_mousePressPos;
TrayPluginItem *m_tray;
int m_dragIndex = -1; // 记录应用区域被拖拽图标的位置
int m_dragIndex = -1; // 记录应用区域被拖拽图标的位置
PluginsItem *m_trashItem; // 垃圾箱插件(需要特殊处理一下)
DockScreen *m_dockScreen;
RecentAppHelper *m_recentHelper;
};
#endif // MAINPANELCONTROL_H

View File

@ -75,6 +75,8 @@ public:
QString itemKey() const;
QSize suitableSize() const;
inline ItemType itemType() const override { return DockItem::StretchPlugin; }
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *e) override;