refactor: the fashion tray item is divided into some modules

the fashion tray item consists of some fixed widget and some wrapper
container.

- double spliter one left and one right
- a control widget
- normal wrapper container
- attention wrapper container(just contains one/zero wrapper)
- hold wrapper container(coming soon)

Change-Id: If307fe0a3160c5478992c734ccac1bdec1071f09
This commit is contained in:
listenerri 2018-12-27 16:54:49 +08:00
parent 902cb3271f
commit 7c1ae86a79
Notes: gerrit 2018-12-27 17:32:03 +08:00
Verified+1: <jenkins@deepin.com>
Code-Review+2: listenerri <listenerri@gmail.com>
Submitted-by: listenerri <listenerri@gmail.com>
Submitted-at: Thu, 27 Dec 2018 17:32:03 +0800
Reviewed-on: https://cr.deepin.io/40935
Project: dde/dde-dock
Branch: refs/heads/dev/drag-and-hold-tray
19 changed files with 1062 additions and 948 deletions

View File

@ -0,0 +1,316 @@
#include "abstractcontainer.h"
#include "../fashiontrayconstants.h"
AbstractContainer::AbstractContainer(TrayPlugin *trayPlugin, QWidget *parent)
: QWidget(parent),
m_trayPlugin(trayPlugin),
m_wrapperLayout(new QBoxLayout(QBoxLayout::LeftToRight)),
m_currentDraggingWrapper(nullptr),
m_expand(true),
m_dockPosition(Dock::Position::Bottom),
m_wrapperSize(QSize(TrayWidgetWidthMin, TrayWidgetHeightMin))
{
m_wrapperLayout->setMargin(0);
m_wrapperLayout->setContentsMargins(0, 0, 0, 0);
m_wrapperLayout->setSpacing(TraySpace);
m_wrapperLayout->setAlignment(Qt::AlignCenter);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setLayout(m_wrapperLayout);
}
void AbstractContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
{
if (!acceptWrapper(wrapper)) {
return;
}
if (containsWrapper(wrapper)) {
return;
}
const int index = whereToInsert(wrapper);
m_wrapperLayout->insertWidget(index, wrapper);
m_wrapperList.insert(index, wrapper);
wrapper->setAttention(false);
wrapper->setFixedSize(m_wrapperSize);
connect(wrapper, &FashionTrayWidgetWrapper::attentionChanged, this, &AbstractContainer::onWrapperAttentionhChanged, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
connect(wrapper, &FashionTrayWidgetWrapper::dragStart, this, &AbstractContainer::onWrapperDragStart, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::dragStop, this, &AbstractContainer::onWrapperDragStop, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::requestSwapWithDragging, this, &AbstractContainer::onWrapperRequestSwapWithDragging, Qt::UniqueConnection);
refreshVisible();
}
bool AbstractContainer::removeWrapper(FashionTrayWidgetWrapper *wrapper)
{
FashionTrayWidgetWrapper *w = takeWrapper(wrapper);
if (!w) {
return false;
}
// do not delete real tray object, just delete it's wrapper object
// the real tray object should be deleted in TrayPlugin class
w->absTrayWidget()->setParent(nullptr);
w->deleteLater();
refreshVisible();
return true;
}
bool AbstractContainer::removeWrapperByTrayWidget(AbstractTrayWidget *trayWidget)
{
FashionTrayWidgetWrapper *w = wrapperByTrayWidget(trayWidget);
if (!w) {
return false;
}
return removeWrapper(w);
}
FashionTrayWidgetWrapper *AbstractContainer::takeWrapper(FashionTrayWidgetWrapper *wrapper)
{
if (!containsWrapper(wrapper)) {
return nullptr;
}
wrapper->disconnect();
m_wrapperLayout->removeWidget(wrapper);
m_wrapperList.removeAll(wrapper);
refreshVisible();
return wrapper;
}
void AbstractContainer::setDockPosition(const Dock::Position pos)
{
m_dockPosition = pos;
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
m_wrapperLayout->setDirection(QBoxLayout::Direction::LeftToRight);
} else{
m_wrapperLayout->setDirection(QBoxLayout::Direction::TopToBottom);
}
refreshVisible();
}
void AbstractContainer::setExpand(const bool expand)
{
m_expand = expand;
refreshVisible();
}
QSize AbstractContainer::totalSize() const
{
QSize size;
const int wrapperWidth = m_wrapperSize.width();
const int wrapperHeight = m_wrapperSize.height();
if (m_dockPosition == Dock::Position::Top || m_dockPosition == Dock::Position::Bottom) {
size.setWidth(
m_wrapperList.size() * wrapperWidth // 所有托盘图标
+ m_wrapperList.size() * TraySpace // 所有托盘图标之间 + 一个尾部的 space
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
m_wrapperList.size() * wrapperHeight // 所有托盘图标
+ m_wrapperList.size() * TraySpace // 所有托盘图标之间 + 一个尾部的 space
);
}
return size;
}
QSize AbstractContainer::sizeHint() const
{
return totalSize();
}
void AbstractContainer::clearWrapper()
{
QList<QPointer<FashionTrayWidgetWrapper>> mList = m_wrapperList;
for (auto wrapper : mList) {
removeWrapper(wrapper);
}
m_wrapperList.clear();
refreshVisible();
}
void AbstractContainer::saveCurrentOrderToConfig()
{
for (int i = 0; i < m_wrapperList.size(); ++i) {
m_trayPlugin->setSortKey(m_wrapperList.at(i)->itemKey(), i + 1);
}
}
void AbstractContainer::setWrapperSize(QSize size)
{
m_wrapperSize = size;
for (auto w : m_wrapperList) {
w->setFixedSize(size);
}
}
bool AbstractContainer::isEmpty()
{
return m_wrapperList.isEmpty();
}
bool AbstractContainer::containsWrapper(FashionTrayWidgetWrapper *wrapper)
{
for (auto w : m_wrapperList) {
if (w->absTrayWidget() == wrapper->absTrayWidget()) {
return true;
}
}
return false;
}
bool AbstractContainer::containsWrapperByTrayWidget(AbstractTrayWidget *trayWidget)
{
if (wrapperByTrayWidget(trayWidget)) {
return true;
}
return false;
}
FashionTrayWidgetWrapper *AbstractContainer::wrapperByTrayWidget(AbstractTrayWidget *trayWidget)
{
for (auto w : m_wrapperList) {
if (w->absTrayWidget() == trayWidget) {
return w;
}
}
return nullptr;
}
int AbstractContainer::whereToInsert(FashionTrayWidgetWrapper *wrapper)
{
if (m_wrapperList.isEmpty()) {
return 0;
}
//根据配置文件记录的顺序排序
const int destSortKey = m_trayPlugin->itemSortKey(wrapper->itemKey());
if (destSortKey < -1) {
return 0;
}
if (destSortKey == -1) {
return m_wrapperList.size();
}
// 当目标插入位置为列表的大小时将从最后面追加到列表中
int destIndex = m_wrapperList.size();
for (int i = 0; i < m_wrapperList.size(); ++i) {
if (destSortKey > m_trayPlugin->itemSortKey(m_wrapperList.at(i)->itemKey())) {
continue;
}
destIndex = i;
break;
}
return destIndex;
}
TrayPlugin *AbstractContainer::trayPlugin() const
{
return m_trayPlugin;
}
QList<QPointer<FashionTrayWidgetWrapper> > AbstractContainer::wrapperList() const
{
return m_wrapperList;
}
QBoxLayout *AbstractContainer::wrapperLayout() const
{
return m_wrapperLayout;
}
bool AbstractContainer::expand() const
{
return m_expand;
}
Dock::Position AbstractContainer::dockPosition() const
{
return m_dockPosition;
}
QSize AbstractContainer::wrapperSize() const
{
return m_wrapperSize;
}
void AbstractContainer::onWrapperAttentionhChanged(const bool attention)
{
FashionTrayWidgetWrapper *wrapper = dynamic_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
Q_EMIT attentionChanged(wrapper, attention);
}
void AbstractContainer::onWrapperDragStart()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
m_currentDraggingWrapper = wrapper;
}
void AbstractContainer::onWrapperDragStop()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
if (m_currentDraggingWrapper == wrapper) {
m_currentDraggingWrapper = nullptr;
} else {
Q_UNREACHABLE();
}
saveCurrentOrderToConfig();
}
void AbstractContainer::onWrapperRequestSwapWithDragging()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper || !m_currentDraggingWrapper || wrapper == m_currentDraggingWrapper) {
return;
}
const int indexOfDest = m_wrapperLayout->indexOf(wrapper);
const int indexOfDragging = m_wrapperLayout->indexOf(m_currentDraggingWrapper);
m_wrapperLayout->removeWidget(m_currentDraggingWrapper);
m_wrapperLayout->insertWidget(indexOfDest, m_currentDraggingWrapper);
m_wrapperList.insert(indexOfDest, m_wrapperList.takeAt(indexOfDragging));
}

View File

@ -0,0 +1,69 @@
#ifndef ABSTRACTCONTAINER_H
#define ABSTRACTCONTAINER_H
#include "constants.h"
#include "trayplugin.h"
#include "../fashiontraywidgetwrapper.h"
#include <QWidget>
class AbstractContainer : public QWidget
{
Q_OBJECT
public:
explicit AbstractContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
virtual bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) = 0;
virtual void refreshVisible() = 0;
virtual void addWrapper(FashionTrayWidgetWrapper *wrapper);
virtual bool removeWrapper(FashionTrayWidgetWrapper *wrapper);
virtual bool removeWrapperByTrayWidget(AbstractTrayWidget *trayWidget);
virtual FashionTrayWidgetWrapper *takeWrapper(FashionTrayWidgetWrapper *wrapper);
virtual void setDockPosition(const Dock::Position pos);
virtual void setExpand(const bool expand);
virtual QSize totalSize() const;
QSize sizeHint() const Q_DECL_OVERRIDE;
void clearWrapper();
void saveCurrentOrderToConfig();
void setWrapperSize(QSize size);
bool isEmpty();
bool containsWrapper(FashionTrayWidgetWrapper *wrapper);
bool containsWrapperByTrayWidget(AbstractTrayWidget *trayWidget);
FashionTrayWidgetWrapper *wrapperByTrayWidget(AbstractTrayWidget *trayWidget);
Q_SIGNALS:
void attentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention);
protected:
virtual int whereToInsert(FashionTrayWidgetWrapper *wrapper);
TrayPlugin *trayPlugin() const;
QList<QPointer<FashionTrayWidgetWrapper>> wrapperList() const;
QBoxLayout *wrapperLayout() const;
bool expand() const;
Dock::Position dockPosition() const;
QSize wrapperSize() const;
private Q_SLOTS:
void onWrapperAttentionhChanged(const bool attention);
void onWrapperDragStart();
void onWrapperDragStop();
void onWrapperRequestSwapWithDragging();
private:
TrayPlugin *m_trayPlugin;
QBoxLayout *m_wrapperLayout;
QPointer<FashionTrayWidgetWrapper> m_currentDraggingWrapper;
QList<QPointer<FashionTrayWidgetWrapper>> m_wrapperList;
bool m_expand;
Dock::Position m_dockPosition;
QSize m_wrapperSize;
};
#endif // ABSTRACTCONTAINER_H

View File

@ -0,0 +1,36 @@
#include "attentioncontainer.h"
AttentionContainer::AttentionContainer(TrayPlugin *trayPlugin, QWidget *parent)
: AbstractContainer(trayPlugin, parent)
{
}
FashionTrayWidgetWrapper *AttentionContainer::takeAttentionWrapper()
{
if (isEmpty()) {
return nullptr;
}
return takeWrapper(wrapperList().first());
}
bool AttentionContainer::acceptWrapper(FashionTrayWidgetWrapper *wrapper)
{
return true;
}
void AttentionContainer::refreshVisible()
{
setVisible(!isEmpty());
}
void AttentionContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
{
if (!isEmpty()) {
qDebug() << "Reject! Already contains a attention wrapper!";
return;
}
AbstractContainer::addWrapper(wrapper);
}

View File

@ -0,0 +1,21 @@
#ifndef ATTENTIONCONTAINER_H
#define ATTENTIONCONTAINER_H
#include "abstractcontainer.h"
class AttentionContainer : public AbstractContainer
{
Q_OBJECT
public:
explicit AttentionContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
FashionTrayWidgetWrapper *takeAttentionWrapper();
// AbstractContainer interface
public:
bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) Q_DECL_OVERRIDE;
void refreshVisible() Q_DECL_OVERRIDE;
void addWrapper(FashionTrayWidgetWrapper *wrapper) Q_DECL_OVERRIDE;
};
#endif // ATTENTIONCONTAINER_H

View File

@ -0,0 +1,6 @@
#include "holdcontainer.h"
HoldContainer::HoldContainer(QWidget *parent) : QWidget(parent)
{
}

View File

@ -0,0 +1,17 @@
#ifndef HOLDCONTAINER_H
#define HOLDCONTAINER_H
#include <QWidget>
class HoldContainer : public QWidget
{
Q_OBJECT
public:
explicit HoldContainer(QWidget *parent = nullptr);
signals:
public slots:
};
#endif // HOLDCONTAINER_H

View File

@ -0,0 +1,150 @@
#include "normalcontainer.h"
NormalContainer::NormalContainer(TrayPlugin *trayPlugin, QWidget *parent)
: AbstractContainer(trayPlugin, parent)
{
}
bool NormalContainer::acceptWrapper(FashionTrayWidgetWrapper *wrapper)
{
Q_UNUSED(wrapper);
return true;
}
void NormalContainer::refreshVisible()
{
setVisible(expand() && !isEmpty());
}
void NormalContainer::setExpand(const bool expand)
{
for (auto w : wrapperList()) {
// reset all tray item attention state
w->setAttention(false);
}
AbstractContainer::setExpand(expand);
}
int NormalContainer::whereToInsert(FashionTrayWidgetWrapper *wrapper)
{
// 如果已经对图标进行过排序则完全按照从配置文件中获取的顺序来插入图标(即父类的实现)
if (trayPlugin()->traysSortedInFashionMode()) {
return AbstractContainer::whereToInsert(wrapper);
}
// 如果没有对图标进行过排序则使用下面的默认排序算法:
// 所有应用图标在系统图标的左侧
// 新的应用图标在最左侧的应用图标处插入
// 新的系统图标在最左侧的系统图标处插入
return whereToInsertByDefault(wrapper);
}
int NormalContainer::whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const
{
int index = 0;
switch (wrapper->absTrayWidget()->trayTyep()) {
case AbstractTrayWidget::TrayType::ApplicationTray:
index = whereToInsertAppTrayByDefault(wrapper);
break;
case AbstractTrayWidget::TrayType::SystemTray:
index = whereToInsertSystemTrayByDefault(wrapper);
break;
default:
Q_UNREACHABLE();
break;
}
return index;
}
int NormalContainer::whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (wrapperList().isEmpty() || wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return 0;
}
int lastAppTrayIndex = -1;
for (int i = 0; i < wrapperList().size(); ++i) {
if (wrapperList().at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::ApplicationTray) {
lastAppTrayIndex = i;
continue;
}
break;
}
// there is no AppTray
if (lastAppTrayIndex == -1) {
return 0;
}
// the inserting tray is not a AppTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return lastAppTrayIndex + 1;
}
int insertIndex = trayPlugin()->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return 0;
}
for (int i = 0; i < wrapperList().size(); ++i) {
if (wrapperList().at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
insertIndex = i;
break;
}
if (insertIndex > trayPlugin()->itemSortKey(wrapperList().at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex > lastAppTrayIndex + 1) {
insertIndex = lastAppTrayIndex + 1;
}
return insertIndex;
}
int NormalContainer::whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (wrapperList().isEmpty()) {
return 0;
}
int firstSystemTrayIndex = -1;
for (int i = 0; i < wrapperList().size(); ++i) {
if (wrapperList().at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
firstSystemTrayIndex = i;
break;
}
}
// there is no SystemTray
if (firstSystemTrayIndex == -1) {
return wrapperList().size();
}
// the inserting tray is not a SystemTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
return firstSystemTrayIndex;
}
int insertIndex = trayPlugin()->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return firstSystemTrayIndex;
}
for (int i = 0; i < wrapperList().size(); ++i) {
if (wrapperList().at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
continue;
}
if (insertIndex > trayPlugin()->itemSortKey(wrapperList().at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex < firstSystemTrayIndex) {
return firstSystemTrayIndex;
}
return insertIndex;
}

View File

@ -0,0 +1,27 @@
#ifndef NORMALCONTAINER_H
#define NORMALCONTAINER_H
#include "abstractcontainer.h"
class NormalContainer : public AbstractContainer
{
Q_OBJECT
public:
explicit NormalContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
// AbstractContainer interface
public:
bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) Q_DECL_OVERRIDE;
void refreshVisible() Q_DECL_OVERRIDE;
void setExpand(const bool expand) Q_DECL_OVERRIDE;
protected:
int whereToInsert(FashionTrayWidgetWrapper *wrapper) Q_DECL_OVERRIDE;
private:
int whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
};
#endif // NORMALCONTAINER_H

View File

@ -0,0 +1,13 @@
#ifndef FASHIONTRAYCONSTANTS_H
#define FASHIONTRAYCONSTANTS_H
namespace Dock {
#define SpliterSize 2
#define TraySpace 10
#define TrayWidgetWidthMin 24
#define TrayWidgetHeightMin 24
}
#endif // FASHIONTRAYCONSTANTS_H

View File

@ -0,0 +1,396 @@
/*
* 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 "fashiontrayitem.h"
#include "fashiontray/fashiontrayconstants.h"
#include "system-trays/systemtrayitem.h"
#include <QDebug>
#include <QResizeEvent>
#define ExpandedKey "fashion-tray-expanded"
int FashionTrayItem::TrayWidgetWidth = TrayWidgetWidthMin;
int FashionTrayItem::TrayWidgetHeight = TrayWidgetHeightMin;
FashionTrayItem::FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent)
: QWidget(parent),
m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_leftSpliter(new QLabel),
m_rightSpliter(new QLabel),
m_attentionDelayTimer(new QTimer(this)),
m_trayPlugin(trayPlugin),
m_controlWidget(new FashionTrayControlWidget(trayPlugin->dockPosition())),
m_currentDraggingTray(nullptr),
m_normalContainer(new NormalContainer(m_trayPlugin)),
m_attentionContainer(new AttentionContainer(m_trayPlugin))
{
setAcceptDrops(true);
m_leftSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_rightSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_controlWidget->setFixedSize(QSize(TrayWidgetWidth, TrayWidgetHeight));
m_normalContainer->setVisible(false);
m_attentionContainer->setVisible(false);
m_mainBoxLayout->setMargin(0);
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
m_mainBoxLayout->setSpacing(TraySpace);
m_mainBoxLayout->addWidget(m_leftSpliter);
m_mainBoxLayout->addWidget(m_normalContainer);
m_mainBoxLayout->addWidget(m_controlWidget);
m_mainBoxLayout->addWidget(m_attentionContainer);
m_mainBoxLayout->addWidget(m_rightSpliter);
m_mainBoxLayout->setAlignment(Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_leftSpliter, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_normalContainer, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_controlWidget, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_attentionContainer, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_rightSpliter, Qt::AlignCenter);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setLayout(m_mainBoxLayout);
m_attentionDelayTimer->setInterval(3000);
m_attentionDelayTimer->setSingleShot(true);
connect(m_controlWidget, &FashionTrayControlWidget::expandChanged, this, &FashionTrayItem::onExpandChanged);
connect(m_normalContainer, &NormalContainer::attentionChanged, this, &FashionTrayItem::onWrapperAttentionChanged);
connect(m_attentionContainer, &NormalContainer::attentionChanged, this, &FashionTrayItem::onWrapperAttentionChanged);
// do not call init immediately the TrayPlugin has not be constructed for now
QTimer::singleShot(0, this, &FashionTrayItem::init);
}
void FashionTrayItem::setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap)
{
clearTrayWidgets();
for (auto it = itemTrayMap.constBegin(); it != itemTrayMap.constEnd(); ++it) {
trayWidgetAdded(it.key(), it.value());
}
}
void FashionTrayItem::trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget)
{
if (m_normalContainer->containsWrapperByTrayWidget(trayWidget)) {
qDebug() << "Reject! want to insert duplicate trayWidget:" << itemKey << trayWidget;
return;
}
FashionTrayWidgetWrapper *wrapper = new FashionTrayWidgetWrapper(itemKey, trayWidget);
do {
if (m_normalContainer->acceptWrapper(wrapper)) {
m_normalContainer->addWrapper(wrapper);
break;
}
} while (false);
requestResize();
}
void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
{
bool deleted = false;
do {
if (m_normalContainer->removeWrapperByTrayWidget(trayWidget)) {
deleted = true;
break;
}
if (m_attentionContainer->removeWrapperByTrayWidget(trayWidget)) {
deleted = true;
break;
}
} while (false);
if (!deleted) {
qDebug() << "Error! can not find the tray widget in fashion tray list" << trayWidget;
}
requestResize();
}
void FashionTrayItem::clearTrayWidgets()
{
m_normalContainer->clearWrapper();
m_attentionContainer->clearWrapper();
requestResize();
}
void FashionTrayItem::setDockPosition(Dock::Position pos)
{
m_controlWidget->setDockPostion(pos);
SystemTrayItem::setDockPostion(pos);
m_normalContainer->setDockPosition(pos);
m_attentionContainer->setDockPosition(pos);
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
m_mainBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
} else{
m_mainBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
}
requestResize();
}
void FashionTrayItem::onExpandChanged(const bool expand)
{
m_trayPlugin->saveValue(ExpandedKey, expand);
refreshHoldContainerPosition();
if (expand) {
m_normalContainer->setExpand(expand);
} else {
// hide all tray immediately if Dock is in maxed size
// the property "DockIsMaxiedSize" of qApp is set by DockSettings class
if (qApp->property("DockIsMaxiedSize").toBool()) {
m_normalContainer->setExpand(expand);
} else {
// hide all tray widget delay for fold animation
QTimer::singleShot(350, this, [=] {
m_normalContainer->setExpand(expand);
});
}
}
m_attentionContainer->setExpand(expand);
m_attentionDelayTimer->start();
attentionWrapperToNormalWrapper();
requestResize();
}
// used by QMetaObject::invokeMethod in TrayPluginItem / MainPanel class
void FashionTrayItem::setSuggestIconSize(QSize size)
{
size = size * 0.6;
int length = qMin(size.width(), size.height());
// 设置最小值
// length = qMax(length, TrayWidgetWidthMin);
if (length == TrayWidgetWidth || length == TrayWidgetHeight) {
return;
}
TrayWidgetWidth = length;
TrayWidgetHeight = length;
QSize newSize(length, length);
m_controlWidget->setFixedSize(newSize);
m_normalContainer->setWrapperSize(newSize);
m_attentionContainer->setWrapperSize(newSize);
requestResize();
}
void FashionTrayItem::setRightSplitVisible(const bool visible)
{
if (visible) {
m_rightSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
} else {
m_rightSpliter->setStyleSheet("background-color: transparent;");
}
}
void FashionTrayItem::showEvent(QShowEvent *event)
{
requestResize();
QWidget::showEvent(event);
}
void FashionTrayItem::hideEvent(QHideEvent *event)
{
requestResize();
QWidget::hideEvent(event);
}
void FashionTrayItem::resizeEvent(QResizeEvent *event)
{
const QSize &mSize = event->size();
const Dock::Position dockPosition = m_trayPlugin->dockPosition();
if (dockPosition == Dock::Position::Top || dockPosition == Dock::Position::Bottom) {
m_leftSpliter->setFixedSize(SpliterSize, mSize.height() * 0.8);
m_rightSpliter->setFixedSize(SpliterSize, mSize.height() * 0.8);
} else{
m_leftSpliter->setFixedSize(mSize.width() * 0.8, SpliterSize);
m_rightSpliter->setFixedSize(mSize.width() * 0.8, SpliterSize);
}
QWidget::resizeEvent(event);
}
void FashionTrayItem::dragEnterEvent(QDragEnterEvent *event)
{
// accept but do not handle the trays drag event
// in order to avoid the for forbidden label displayed on the mouse
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
event->accept();
return;
}
QWidget::dragEnterEvent(event);
}
QSize FashionTrayItem::sizeHint() const
{
return wantedTotalSize();
}
void FashionTrayItem::init()
{
qDebug() << "init Fashion mode tray plugin item";
m_controlWidget->setExpanded(m_trayPlugin->getValue(ExpandedKey, true).toBool());
setDockPosition(m_trayPlugin->dockPosition());
onExpandChanged(m_controlWidget->expanded());
}
QSize FashionTrayItem::wantedTotalSize() const
{
QSize size;
const Dock::Position dockPosition = m_trayPlugin->dockPosition();
if (m_controlWidget->expanded()) {
if (dockPosition == Dock::Position::Top || dockPosition == Dock::Position::Bottom) {
size.setWidth(
SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ TrayWidgetWidth // 控制按钮
+ m_normalContainer->sizeHint().width() // 普通区域
// + m_holdContainer->sizeHint().width() // 保留区域
+ m_attentionContainer->sizeHint().width() // 活动区域
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ TrayWidgetWidth // 控制按钮
+ m_normalContainer->sizeHint().height() // 普通区域
// + m_holdContainer->sizeHint().height() // 保留区域
+ m_attentionContainer->sizeHint().height() // 活动区域
);
}
} else {
if (dockPosition == Dock::Position::Top || dockPosition == Dock::Position::Bottom) {
size.setWidth(
SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ TrayWidgetWidth // 控制按钮
// + m_holdContainer->sizeHint().width() // 保留区域
+ m_attentionContainer->sizeHint().width() // 活动区域
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ TrayWidgetWidth // 控制按钮
// + m_holdContainer->sizeHint().height() // 保留区域
+ m_attentionContainer->sizeHint().height() // 活动区域
);
}
}
return size;
}
void FashionTrayItem::onWrapperAttentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention)
{
if (m_controlWidget->expanded()) {
return;
}
// 在timer处于Active状态期间不设置新的活动图标
if (attention && m_attentionDelayTimer->isActive()) {
return;
}
if (attention) {
// ignore the attention which is come from AttentionContainer
if (m_attentionContainer->containsWrapper(wrapper)) {
return;
}
// move previous attention wrapper from AttentionContainer to NormalContainer
attentionWrapperToNormalWrapper();
// move current attention wrapper from NormalContainer to AttentionContainer
normalWrapperToAttentionWrapper(wrapper);
} else {
// only focus the disattention from AttentionContainer
if (m_attentionContainer->containsWrapper(wrapper)) {
attentionWrapperToNormalWrapper();
}
}
m_attentionDelayTimer->start();
requestResize();
}
void FashionTrayItem::attentionWrapperToNormalWrapper()
{
FashionTrayWidgetWrapper *preAttentionWrapper = m_attentionContainer->takeAttentionWrapper();
if (preAttentionWrapper) {
m_normalContainer->addWrapper(preAttentionWrapper);
}
}
void FashionTrayItem::normalWrapperToAttentionWrapper(FashionTrayWidgetWrapper *wrapper)
{
FashionTrayWidgetWrapper *attentionWrapper = m_normalContainer->takeWrapper(wrapper);
if (attentionWrapper) {
m_attentionContainer->addWrapper(attentionWrapper);
} else {
qDebug() << "Warnning: not find the attention wrapper in NormalContainer";
}
}
void FashionTrayItem::requestResize()
{
// reset property "FashionTraySize" to notify dock resize
// DockPluginsController will watch this property
setProperty("FashionTraySize", sizeHint());
}
void FashionTrayItem::refreshHoldContainerPosition()
{
// const int destIndex = m_mainBoxLayout->indexOf(m_controlWidget)
// + (m_controlWidget->expanded() ? 0 : 1);
// m_mainBoxLayout->insertWidget(destIndex, m_holdContainer);
}

View File

@ -26,7 +26,8 @@
#include "trayplugin.h"
#include "fashiontraywidgetwrapper.h"
#include "fashiontraycontrolwidget.h"
#include "fashiontrayholdcontainer.h"
#include "containers/normalcontainer.h"
#include "containers/attentioncontainer.h"
#include <QWidget>
#include <QPointer>
@ -47,13 +48,13 @@ public:
void trayWidgetRemoved(AbstractTrayWidget *trayWidget);
void clearTrayWidgets();
void setDockPostion(Dock::Position pos);
void setDockPosition(Dock::Position pos);
inline static int trayWidgetWidth() {return TrayWidgetWidth;}
inline static int trayWidgetHeight() {return TrayWidgetHeight;}
public slots:
void onTrayListExpandChanged(const bool expand);
void onExpandChanged(const bool expand);
void setSuggestIconSize(QSize size);
void setRightSplitVisible(const bool visible);
@ -67,43 +68,26 @@ protected:
private:
void init();
QSize wantedTotalSize() const;
int whereToInsert(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertBySortKey(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
int whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
void saveCurrentOrderToConfig();
private Q_SLOTS:
void onTrayAttentionChanged(const bool attention);
void setCurrentAttentionTray(FashionTrayWidgetWrapper *attentionWrapper);
void onWrapperAttentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention);
void attentionWrapperToNormalWrapper();
void normalWrapperToAttentionWrapper(FashionTrayWidgetWrapper *wrapper);
void requestResize();
void moveOutAttionTray();
void moveInAttionTray();
void switchAttionTray(FashionTrayWidgetWrapper *attentionWrapper);
void refreshHoldContainerPosition();
void refreshTraysVisible();
void onItemDragStart();
void onItemDragStop();
void onItemRequestSwapWithDragging();
private:
QBoxLayout *m_mainBoxLayout;
QBoxLayout *m_trayBoxLayout;
QLabel *m_leftSpliter;
QLabel *m_rightSpliter;
QTimer *m_attentionDelayTimer;
Dock::Position m_dockPosistion;
TrayPlugin *m_trayPlugin;
FashionTrayControlWidget *m_controlWidget;
FashionTrayWidgetWrapper *m_currentAttentionTray;
FashionTrayWidgetWrapper *m_currentDraggingTray;
FashionTrayHoldContainer *m_holdContainer;
QList<QPointer<FashionTrayWidgetWrapper>> m_totalWrapperList;
QList<QPointer<FashionTrayWidgetWrapper>> m_normalWrapperList;
NormalContainer *m_normalContainer;
AttentionContainer *m_attentionContainer;
static int TrayWidgetWidth;
static int TrayWidgetHeight;

View File

@ -1,176 +0,0 @@
#include "fashiontrayholdcontainer.h"
#include "fashiontrayitem.h"
#define SpliterSize 2
#define TraySpace 10
FashionTrayHoldContainer::FashionTrayHoldContainer(TrayPlugin *trayPlugin, QWidget *parent)
: QWidget(parent),
m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_holdSpliter(new QLabel),
m_trayPlugin(trayPlugin),
m_dockPosistion(trayPlugin->dockPosition())
{
setAcceptDrops(true);
m_holdSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_mainBoxLayout->setMargin(0);
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
m_mainBoxLayout->setSpacing(TraySpace);
m_mainBoxLayout->addWidget(m_holdSpliter);
m_mainBoxLayout->setAlignment(Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_holdSpliter, Qt::AlignCenter);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setLayout(m_mainBoxLayout);
}
void FashionTrayHoldContainer::setDockPostion(Dock::Position pos)
{
m_dockPosistion = pos;
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
m_mainBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
} else{
m_mainBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
}
}
void FashionTrayHoldContainer::setTrayExpand(const bool expand)
{
m_expand = expand;
// 将显示与隐藏放在 timer 里做以避免收起动画的一些抖动发生
QTimer::singleShot(200, this, [=] {
// 这行代码的逻辑与下面被注释掉的部分相同
setVisible(!(!m_expand && m_holdWrapperList.isEmpty()));
// if (m_expand) {
// setVisible(true);
// } else {
// if (m_holdWrapperList.isEmpty()) {
// setVisible(false);
// } else {
// setVisible(true);
// }
// }
});
}
bool FashionTrayHoldContainer::exists(FashionTrayWidgetWrapper *wrapper) const
{
for (auto w : m_holdWrapperList) {
}
return false;
}
bool FashionTrayHoldContainer::isHoldTrayWrapper(FashionTrayWidgetWrapper *wrapper) const
{
const QString &key = QString("%1_hold").arg(wrapper->itemKey());
return m_trayPlugin->getValue(key, false).toBool();
}
void FashionTrayHoldContainer::addTrayWrapper(FashionTrayWidgetWrapper *wrapper)
{
const QString &key = QString("%1_hold").arg(wrapper->itemKey());
m_trayPlugin->saveValue(key, true);
const int index = whereToInsert(wrapper);
m_mainBoxLayout->insertWidget(index, wrapper);
m_holdWrapperList.insert(index, wrapper);
}
bool FashionTrayHoldContainer::removeTrayWrapper(FashionTrayWidgetWrapper *wrapper)
{
return false;
const QString &key = QString("%1_hold").arg(wrapper->itemKey());
m_trayPlugin->saveValue(key, false);
}
int FashionTrayHoldContainer::whereToInsert(FashionTrayWidgetWrapper *wrapper) const
{
if (m_holdWrapperList.isEmpty()) {
return 0;
}
const int destSortKey = m_trayPlugin->itemSortKey(wrapper->itemKey());
if (destSortKey < -1) {
return 0;
}
if (destSortKey == -1) {
return m_holdWrapperList.size();
}
// 当目标插入位置为列表的大小时将从最后面追加到列表中
int destIndex = m_holdWrapperList.size();
for (int i = 0; i < m_holdWrapperList.size(); ++i) {
if (destSortKey > m_trayPlugin->itemSortKey(m_holdWrapperList.at(i)->itemKey())) {
continue;
}
destIndex = i;
break;
}
return destIndex;
}
QSize FashionTrayHoldContainer::sizeHint() const
{
QSize size;
const int TrayWidgetWidth = FashionTrayItem::trayWidgetWidth();
const int TrayWidgetHeight = FashionTrayItem::trayWidgetHeight();
if (m_expand) {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
size.setWidth(
m_holdWrapperList.size() * TrayWidgetWidth // 所有保留显示的托盘图标
+ SpliterSize // 一个分隔条
+ (m_holdWrapperList.size() + 1) * TraySpace // 所有托盘图标之间的 space + 一个分隔条的 space
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
m_holdWrapperList.size() * TrayWidgetHeight // 所有保留显示的托盘图标
+ SpliterSize // 一个分隔条
+ (m_holdWrapperList.size() + 1) * TraySpace // 所有托盘图标之间的 space + 一个分隔条的 space
);
}
} else {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
size.setWidth(
m_holdWrapperList.size() * TrayWidgetWidth // 所有保留显示的托盘图标
+ m_holdWrapperList.size() * TraySpace // 所有托盘图标之间的 space
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
m_holdWrapperList.size() * TrayWidgetHeight // 所有保留显示的托盘图标
+ m_holdWrapperList.size() * TraySpace // 所有托盘图标之间的 space
);
}
}
return size;
}
void FashionTrayHoldContainer::resizeEvent(QResizeEvent *event)
{
const QSize &mSize = event->size();
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
m_holdSpliter->setFixedSize(SpliterSize, mSize.height() * 0.3);
} else{
m_holdSpliter->setFixedSize(mSize.width() * 0.3, SpliterSize);
}
QWidget::resizeEvent(event);
}

View File

@ -1,46 +0,0 @@
#ifndef FASHIONTRAYHOLDCONTAINER_H
#define FASHIONTRAYHOLDCONTAINER_H
#include "constants.h"
#include "trayplugin.h"
#include "fashiontraywidgetwrapper.h"
#include <QWidget>
#include <QBoxLayout>
#include <QLabel>
class FashionTrayHoldContainer : public QWidget
{
Q_OBJECT
public:
explicit FashionTrayHoldContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
void setDockPostion(Dock::Position pos);
void setTrayExpand(const bool expand);
bool exists(FashionTrayWidgetWrapper *wrapper) const;
bool isHoldTrayWrapper(FashionTrayWidgetWrapper *wrapper) const;
void addTrayWrapper(FashionTrayWidgetWrapper *wrapper);
bool removeTrayWrapper(FashionTrayWidgetWrapper *wrapper);
int whereToInsert(FashionTrayWidgetWrapper *wrapper) const;
public:
QSize sizeHint() const Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
private:
QBoxLayout *m_mainBoxLayout;
QLabel *m_holdSpliter;
TrayPlugin *m_trayPlugin;
bool m_expand;
Dock::Position m_dockPosistion;
QList<QPointer<FashionTrayWidgetWrapper>> m_holdWrapperList;
};
#endif // FASHIONTRAYHOLDCONTAINER_H

View File

@ -1,699 +0,0 @@
/*
* 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 "fashiontrayitem.h"
#include "system-trays/systemtrayitem.h"
#include <QDebug>
#include <QResizeEvent>
#define SpliterSize 2
#define TraySpace 10
#define TrayWidgetWidthMin 24
#define TrayWidgetHeightMin 24
#define ExpandedKey "fashion-tray-expanded"
int FashionTrayItem::TrayWidgetWidth = TrayWidgetWidthMin;
int FashionTrayItem::TrayWidgetHeight = TrayWidgetHeightMin;
FashionTrayItem::FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent)
: QWidget(parent),
m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_trayBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight)),
m_leftSpliter(new QLabel),
m_rightSpliter(new QLabel),
m_attentionDelayTimer(new QTimer(this)),
m_dockPosistion(trayPlugin->dockPosition()),
m_trayPlugin(trayPlugin),
m_controlWidget(new FashionTrayControlWidget(m_dockPosistion)),
m_currentAttentionTray(nullptr),
m_currentDraggingTray(nullptr),
m_holdContainer(new FashionTrayHoldContainer(m_trayPlugin))
{
setAcceptDrops(true);
m_leftSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_rightSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
m_controlWidget->setFixedSize(QSize(TrayWidgetWidth, TrayWidgetHeight));
m_mainBoxLayout->setMargin(0);
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
m_mainBoxLayout->setSpacing(TraySpace);
m_trayBoxLayout->setMargin(0);
m_trayBoxLayout->setContentsMargins(0, 0, 0, 0);
m_trayBoxLayout->setSpacing(TraySpace);
m_mainBoxLayout->addWidget(m_leftSpliter);
m_mainBoxLayout->addLayout(m_trayBoxLayout);
m_mainBoxLayout->addWidget(m_holdContainer);
m_mainBoxLayout->addWidget(m_controlWidget);
m_mainBoxLayout->addWidget(m_rightSpliter);
m_mainBoxLayout->setAlignment(Qt::AlignCenter);
m_trayBoxLayout->setAlignment(Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_leftSpliter, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_holdContainer, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_controlWidget, Qt::AlignCenter);
m_mainBoxLayout->setAlignment(m_rightSpliter, Qt::AlignCenter);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setLayout(m_mainBoxLayout);
m_attentionDelayTimer->setInterval(3000);
m_attentionDelayTimer->setSingleShot(true);
connect(m_controlWidget, &FashionTrayControlWidget::expandChanged, this, &FashionTrayItem::onTrayListExpandChanged);
// do not call init immediately the TrayPlugin has not be constructed for now
QTimer::singleShot(0, this, &FashionTrayItem::init);
}
void FashionTrayItem::setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap)
{
clearTrayWidgets();
for (auto it = itemTrayMap.constBegin(); it != itemTrayMap.constEnd(); ++it) {
trayWidgetAdded(it.key(), it.value());
}
}
void FashionTrayItem::trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget)
{
for (auto w : m_totalWrapperList) {
if (w->absTrayWidget() == trayWidget) {
qDebug() << "Reject! want to insert duplicate trayWidget:" << itemKey << trayWidget;
return;
}
}
FashionTrayWidgetWrapper *wrapper = new FashionTrayWidgetWrapper(itemKey, trayWidget);
wrapper->setFixedSize(QSize(TrayWidgetWidth, TrayWidgetHeight));
const int index = whereToInsert(wrapper);
m_trayBoxLayout->insertWidget(index, wrapper);
m_normalWrapperList.insert(index, wrapper);
wrapper->setVisible(m_controlWidget->expanded());
if (wrapper->attention()) {
setCurrentAttentionTray(wrapper);
}
connect(wrapper, &FashionTrayWidgetWrapper::attentionChanged, this, &FashionTrayItem::onTrayAttentionChanged, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
connect(wrapper, &FashionTrayWidgetWrapper::dragStart, this, &FashionTrayItem::onItemDragStart, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::dragStop, this, &FashionTrayItem::onItemDragStop, Qt::UniqueConnection);
connect(wrapper, &FashionTrayWidgetWrapper::requestSwapWithDragging, this, &FashionTrayItem::onItemRequestSwapWithDragging, Qt::UniqueConnection);
requestResize();
}
void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
{
bool founded = false;
for (auto wrapper : m_normalWrapperList) {
// found the removed tray
if (wrapper->absTrayWidget() == trayWidget) {
// the removed tray is a attention tray
if (m_currentAttentionTray == wrapper) {
if (m_controlWidget->expanded()) {
m_trayBoxLayout->removeWidget(m_currentAttentionTray);
} else {
m_mainBoxLayout->removeWidget(m_currentAttentionTray);
}
m_currentAttentionTray = nullptr;
} else {
m_trayBoxLayout->removeWidget(wrapper);
}
// do not delete real tray object, just delete it's wrapper object
// the real tray object should be deleted in TrayPlugin class
trayWidget->setParent(nullptr);
wrapper->deleteLater();
m_normalWrapperList.removeAll(wrapper);
founded = true;
break;
}
}
if (!founded) {
qDebug() << "Error! can not find the tray widget in fashion tray list" << trayWidget;
}
requestResize();
}
void FashionTrayItem::clearTrayWidgets()
{
QList<QPointer<FashionTrayWidgetWrapper>> mList = m_normalWrapperList;
for (auto wrapper : mList) {
trayWidgetRemoved(wrapper->absTrayWidget());
}
m_normalWrapperList.clear();
requestResize();
}
void FashionTrayItem::setDockPostion(Dock::Position pos)
{
m_dockPosistion = pos;
m_controlWidget->setDockPostion(m_dockPosistion);
SystemTrayItem::setDockPostion(m_dockPosistion);
m_holdContainer->setDockPostion(m_dockPosistion);
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
m_mainBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_trayBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
} else{
m_mainBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_trayBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
}
requestResize();
}
void FashionTrayItem::onTrayListExpandChanged(const bool expand)
{
m_trayPlugin->saveValue(ExpandedKey, expand);
m_holdContainer->setTrayExpand(expand);
refreshHoldContainerPosition();
if (!isVisible())
return;
if (expand) {
refreshTraysVisible();
} else {
// hide all tray immediately if Dock is in maxed size
// the property "DockIsMaxiedSize" of qApp is set by DockSettings class
if (qApp->property("DockIsMaxiedSize").toBool()) {
refreshTraysVisible();
} else {
// hide all tray widget delay for fold animation
QTimer::singleShot(350, this, [=] {refreshTraysVisible();});
}
requestResize();
}
}
// used by QMetaObject::invokeMethod in TrayPluginItem / MainPanel class
void FashionTrayItem::setSuggestIconSize(QSize size)
{
size = size * 0.6;
int length = qMin(size.width(), size.height());
// 设置最小值
// length = qMax(length, TrayWidgetWidthMin);
if (length == TrayWidgetWidth || length == TrayWidgetHeight) {
return;
}
TrayWidgetWidth = length;
TrayWidgetHeight = length;
QSize newSize(length, length);
m_controlWidget->setFixedSize(newSize);
for (auto wrapper : m_normalWrapperList) {
wrapper->setFixedSize(newSize);
}
requestResize();
}
void FashionTrayItem::setRightSplitVisible(const bool visible)
{
if (visible) {
m_rightSpliter->setStyleSheet("background-color: rgba(255, 255, 255, 0.1);");
} else {
m_rightSpliter->setStyleSheet("background-color: transparent;");
}
}
void FashionTrayItem::showEvent(QShowEvent *event)
{
requestResize();
QWidget::showEvent(event);
}
void FashionTrayItem::hideEvent(QHideEvent *event)
{
requestResize();
QWidget::hideEvent(event);
}
void FashionTrayItem::resizeEvent(QResizeEvent *event)
{
const QSize &mSize = event->size();
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
m_leftSpliter->setFixedSize(SpliterSize, mSize.height() * 0.8);
m_rightSpliter->setFixedSize(SpliterSize, mSize.height() * 0.8);
} else{
m_leftSpliter->setFixedSize(mSize.width() * 0.8, SpliterSize);
m_rightSpliter->setFixedSize(mSize.width() * 0.8, SpliterSize);
}
QWidget::resizeEvent(event);
}
void FashionTrayItem::dragEnterEvent(QDragEnterEvent *event)
{
// accept but do not handle the trays drag event
// in order to avoid the for forbidden label displayed on the mouse
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
event->accept();
return;
}
QWidget::dragEnterEvent(event);
}
QSize FashionTrayItem::sizeHint() const
{
return wantedTotalSize();
}
void FashionTrayItem::init()
{
qDebug() << "init Fashion mode tray plugin item";
m_controlWidget->setExpanded(m_trayPlugin->getValue(ExpandedKey, true).toBool());
setDockPostion(m_dockPosistion);
onTrayListExpandChanged(m_controlWidget->expanded());
}
QSize FashionTrayItem::wantedTotalSize() const
{
QSize size;
// 保留区域的边界后面跟着的一个 space 由其自己计算
if (m_controlWidget->expanded()) {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
size.setWidth(
m_normalWrapperList.size() * TrayWidgetWidth // 所有托盘图标
+ TrayWidgetWidth // 控制按钮
+ SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ m_normalWrapperList.size() * TraySpace // TrayBoxLayout 中所有 space + 后面跟一个 space
+ m_holdContainer->sizeHint().width() // 保留区域的宽
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
m_normalWrapperList.size() * TrayWidgetHeight // 所有托盘图标
+ TrayWidgetHeight // 控制按钮
+ SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ m_normalWrapperList.size() * TraySpace // TrayBoxLayout 中所有 space + 后面跟一个 space
+ m_holdContainer->sizeHint().height() // 保留区域的高
);
}
} else {
if (m_dockPosistion == Dock::Position::Top || m_dockPosistion == Dock::Position::Bottom) {
size.setWidth(
TrayWidgetWidth // 控制按钮
+ (m_currentAttentionTray ? TrayWidgetWidth : 0) // 活动状态的 tray
+ SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ (m_currentAttentionTray ? TraySpace : 0) // 活动状态的 tray 的 space
+ m_holdContainer->sizeHint().width() // 保留区域的宽
);
size.setHeight(height());
} else {
size.setWidth(width());
size.setHeight(
TrayWidgetHeight // 控制按钮
+ (m_currentAttentionTray ? TrayWidgetWidth : 0) // 活动状态的tray
+ SpliterSize * 2 // 两个分隔条
+ TraySpace * 2 // 两个分隔条旁边的 space
+ (m_currentAttentionTray ? TraySpace : 0) // 活动状态的 tray 的 space
+ m_holdContainer->sizeHint().height() // 保留区域的高
);
}
}
return size;
}
int FashionTrayItem::whereToInsert(FashionTrayWidgetWrapper *wrapper) const
{
// 如果已经对图标进行过排序则完全按照从配置文件中获取的顺序来插入图标
if (m_trayPlugin->traysSortedInFashionMode()) {
return whereToInsertBySortKey(wrapper);
}
// 如果没有对图标进行过排序则使用下面的默认排序算法:
// 所有应用图标在系统图标的左侧
// 新的应用图标在最左侧的应用图标处插入
// 新的系统图标在最左侧的系统图标处插入
return whereToInsertByDefault(wrapper);
}
int FashionTrayItem::whereToInsertBySortKey(FashionTrayWidgetWrapper *wrapper) const
{
if (m_normalWrapperList.isEmpty()) {
return 0;
}
const int destSortKey = m_trayPlugin->itemSortKey(wrapper->itemKey());
if (destSortKey < -1) {
return 0;
}
if (destSortKey == -1) {
return m_normalWrapperList.size();
}
// 当目标插入位置为列表的大小时将从最后面追加到列表中
int destIndex = m_normalWrapperList.size();
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
if (destSortKey > m_trayPlugin->itemSortKey(m_normalWrapperList.at(i)->itemKey())) {
continue;
}
destIndex = i;
break;
}
return destIndex;
}
int FashionTrayItem::whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const
{
int index = 0;
switch (wrapper->absTrayWidget()->trayTyep()) {
case AbstractTrayWidget::TrayType::ApplicationTray:
index = whereToInsertAppTrayByDefault(wrapper);
break;
case AbstractTrayWidget::TrayType::SystemTray:
index = whereToInsertSystemTrayByDefault(wrapper);
break;
default:
Q_UNREACHABLE();
break;
}
return index;
}
int FashionTrayItem::whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (m_normalWrapperList.isEmpty() || wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return 0;
}
int lastAppTrayIndex = -1;
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
if (m_normalWrapperList.at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::ApplicationTray) {
lastAppTrayIndex = i;
continue;
}
break;
}
// there is no AppTray
if (lastAppTrayIndex == -1) {
return 0;
}
// the inserting tray is not a AppTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
return lastAppTrayIndex + 1;
}
int insertIndex = m_trayPlugin->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return 0;
}
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
if (m_normalWrapperList.at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
insertIndex = i;
break;
}
if (insertIndex > m_trayPlugin->itemSortKey(m_normalWrapperList.at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex > lastAppTrayIndex + 1) {
insertIndex = lastAppTrayIndex + 1;
}
return insertIndex;
}
int FashionTrayItem::whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
{
if (m_normalWrapperList.isEmpty()) {
return 0;
}
int firstSystemTrayIndex = -1;
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
if (m_normalWrapperList.at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
firstSystemTrayIndex = i;
break;
}
}
// there is no SystemTray
if (firstSystemTrayIndex == -1) {
return m_normalWrapperList.size();
}
// the inserting tray is not a SystemTray
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
return firstSystemTrayIndex;
}
int insertIndex = m_trayPlugin->itemSortKey(wrapper->itemKey());
// invalid index
if (insertIndex < -1) {
return firstSystemTrayIndex;
}
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
if (m_normalWrapperList.at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
continue;
}
if (insertIndex > m_trayPlugin->itemSortKey(m_normalWrapperList.at(i)->itemKey())) {
continue;
}
insertIndex = i;
break;
}
if (insertIndex < firstSystemTrayIndex) {
return firstSystemTrayIndex;
}
return insertIndex;
}
void FashionTrayItem::saveCurrentOrderToConfig()
{
for (int i = 0; i < m_normalWrapperList.size(); ++i) {
m_trayPlugin->setSortKey(m_normalWrapperList.at(i)->itemKey(), i + 1);
}
}
void FashionTrayItem::onTrayAttentionChanged(const bool attention)
{
// 设置attention为false之后启动timer在timer处于Active状态期间不重设attention为true
if (!attention) {
m_attentionDelayTimer->start();
} else if (attention && m_attentionDelayTimer->isActive()) {
return;
}
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
Q_ASSERT(wrapper);
if (attention) {
setCurrentAttentionTray(wrapper);
} else {
if (m_currentAttentionTray != wrapper) {
return;
}
if (m_controlWidget->expanded()) {
m_currentAttentionTray = nullptr;
} else {
moveInAttionTray();
m_currentAttentionTray = nullptr;
requestResize();
}
}
}
void FashionTrayItem::setCurrentAttentionTray(FashionTrayWidgetWrapper *attentionWrapper)
{
if (!attentionWrapper) {
return;
}
if (m_controlWidget->expanded()) {
m_currentAttentionTray = attentionWrapper;
} else {
if (m_currentAttentionTray == attentionWrapper) {
return;
}
moveInAttionTray(); // move current attention tray to hide area
bool sizeChanged = !m_currentAttentionTray;
m_currentAttentionTray = attentionWrapper;
moveOutAttionTray(); // move out current attention tray
if (sizeChanged) {
requestResize();
}
}
m_mainBoxLayout->setAlignment(m_currentAttentionTray, Qt::AlignCenter);
}
void FashionTrayItem::requestResize()
{
// reset property "FashionTraySize" to notify dock resize
// DockPluginsController will watch this property
setProperty("FashionTraySize", sizeHint());
}
void FashionTrayItem::moveOutAttionTray()
{
if (!m_currentAttentionTray) {
return;
}
m_trayBoxLayout->removeWidget(m_currentAttentionTray);
m_mainBoxLayout->insertWidget(m_mainBoxLayout->indexOf(m_rightSpliter), m_currentAttentionTray);
m_currentAttentionTray->setVisible(true);
}
void FashionTrayItem::moveInAttionTray()
{
if (!m_currentAttentionTray) {
return;
}
m_mainBoxLayout->removeWidget(m_currentAttentionTray);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
m_currentAttentionTray->setVisible(false);
m_currentAttentionTray->setAttention(false);
}
void FashionTrayItem::switchAttionTray(FashionTrayWidgetWrapper *attentionWrapper)
{
if (!m_currentAttentionTray || !attentionWrapper) {
return;
}
m_mainBoxLayout->replaceWidget(m_currentAttentionTray, attentionWrapper);
m_trayBoxLayout->removeWidget(attentionWrapper);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
attentionWrapper->setVisible(true);
m_currentAttentionTray->setVisible(m_controlWidget->expanded());
m_currentAttentionTray = attentionWrapper;
}
void FashionTrayItem::refreshHoldContainerPosition()
{
const int destIndex = m_mainBoxLayout->indexOf(m_controlWidget)
+ (m_controlWidget->expanded() ? 0 : 1);
m_mainBoxLayout->insertWidget(destIndex, m_holdContainer);
}
void FashionTrayItem::refreshTraysVisible()
{
const bool expand = m_controlWidget->expanded();
if (m_currentAttentionTray) {
if (expand) {
m_mainBoxLayout->removeWidget(m_currentAttentionTray);
m_trayBoxLayout->insertWidget(whereToInsert(m_currentAttentionTray), m_currentAttentionTray);
}
m_currentAttentionTray = nullptr;
}
for (auto wrapper : m_normalWrapperList) {
wrapper->setVisible(expand);
// reset all tray item attention state
wrapper->setAttention(false);
}
m_attentionDelayTimer->start();
requestResize();
}
void FashionTrayItem::onItemDragStart()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
m_currentDraggingTray = wrapper;
}
void FashionTrayItem::onItemDragStop()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper) {
return;
}
if (m_currentDraggingTray == wrapper) {
m_currentDraggingTray = nullptr;
} else {
Q_UNREACHABLE();
}
saveCurrentOrderToConfig();
}
void FashionTrayItem::onItemRequestSwapWithDragging()
{
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
if (!wrapper || !m_currentDraggingTray || wrapper == m_currentDraggingTray) {
return;
}
const int indexOfDest = m_trayBoxLayout->indexOf(wrapper);
const int indexOfDragging = m_trayBoxLayout->indexOf(m_currentDraggingTray);
m_trayBoxLayout->removeWidget(m_currentDraggingTray);
m_trayBoxLayout->insertWidget(indexOfDest, m_currentDraggingTray);
m_normalWrapperList.insert(indexOfDest, m_normalWrapperList.takeAt(indexOfDragging));
}

View File

@ -21,7 +21,7 @@
*/
#include "trayplugin.h"
#include "fashiontrayitem.h"
#include "fashiontray/fashiontrayitem.h"
#include "snitraywidget.h"
#include <QDir>
@ -125,7 +125,7 @@ void TrayPlugin::positionChanged(const Dock::Position position)
return;
}
m_fashionItem->setDockPostion(position);
m_fashionItem->setDockPosition(position);
}
QWidget *TrayPlugin::itemWidget(const QString &itemKey)