/* * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. * * Author: donghualin * * Maintainer: donghualin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "traymanagerwindow.h" #include "quickpluginwindow.h" #include "tray_gridview.h" #include "tray_delegate.h" #include "tray_model.h" #include "constants.h" #include "quicksettingcontainer.h" #include "systempluginwindow.h" #include "datetimedisplayer.h" #include #include #include #include #include #include #include #include #include #define MAXFIXEDSIZE 999999 #define CRITLCALHEIGHT 42 #define CONTENTSPACE 7 // 高度小于等于这个值的时候,间距最小值 #define MINHIGHT 46 // 最小值与最大值的差值 #define MINSPACE 4 // 当前高度与最小高度差值大于这个值的时候,间距使用最大值 #define MAXDIFF 3 TrayManagerWindow::TrayManagerWindow(QWidget *parent) : QWidget(parent) , m_appPluginDatetimeWidget(new QWidget(this)) , m_systemPluginWidget(new SystemPluginWindow(this)) , m_appPluginWidget(new QWidget(m_appPluginDatetimeWidget)) , m_quickIconWidget(new QuickPluginWindow(m_appPluginWidget)) , m_dateTimeWidget(new DateTimeDisplayer(false, m_appPluginDatetimeWidget)) , m_appPluginLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this)) , m_mainLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this)) , m_trayView(new TrayGridView(this)) , m_model(TrayModel::getDockModel()) , m_delegate(new TrayDelegate(m_trayView, m_trayView)) , m_position(Dock::Position::Bottom) , m_displayMode(Dock::DisplayMode::Fashion) , m_splitLine(new QLabel(m_appPluginDatetimeWidget)) , m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) , m_singleShow(false) , m_borderRadius(0) { initUi(); initConnection(); setAcceptDrops(true); setMouseTracking(true); QMetaObject::invokeMethod(this, &TrayManagerWindow::updateLayout, Qt::QueuedConnection); } TrayManagerWindow::~TrayManagerWindow() { } void TrayManagerWindow::updateBorderRadius(int borderRadius) { m_borderRadius = borderRadius; update(); } void TrayManagerWindow::updateLayout() { bool lastIsSingle = m_singleShow; if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) m_singleShow = (height() <= CRITLCALHEIGHT); else m_singleShow = true; if (m_singleShow) resetSingleDirection(); else resetMultiDirection(); resetChildWidgetSize(); // 当尺寸发生变化的时候,通知托盘区域刷新尺寸,让托盘图标始终保持居中显示 Q_EMIT m_delegate->sizeHintChanged(m_model->index(0, 0)); // 当插件区域从单行变成两行或者两行变成单行的时候,发送该信号,通知外部重新调整区域大小 if (lastIsSingle != m_singleShow) Q_EMIT requestUpdate(); } void TrayManagerWindow::setPositon(Dock::Position position) { if (m_position == position) return; m_position = position; if (position == Dock::Position::Top || position == Dock::Position::Bottom) m_trayView->setOrientation(QListView::Flow::LeftToRight, false); else m_trayView->setOrientation(QListView::Flow::TopToBottom, false); TrayDelegate *delegate = static_cast(m_trayView->itemDelegate()); delegate->setPositon(position); m_trayView->setPosition(position); m_quickIconWidget->setPositon(position); m_dateTimeWidget->setPositon(position); m_systemPluginWidget->setPositon(position); if (m_model->hasExpand()) { // 切换位置的时候,需要先关闭编辑器,然后在model函数的flag方法中打开 m_trayView->closePersistentEditor(m_model->index(0, 0)); } updateLayout(); } void TrayManagerWindow::setDisplayMode(Dock::DisplayMode displayMode) { m_displayMode = displayMode; // 从时尚模式切换到高效模式的时候,需要重新布局 onTrayCountChanged(); } int TrayManagerWindow::appDatetimeSize(const Dock::Position &position) const { if (position == Dock::Position::Top || position == Dock::Position::Bottom) { bool showSingle = m_singleShow; // 正在从左右切换到上下(m_position当前显示的位置,还未切换),此时根据托盘区域的尺寸来决定显示一行还是两行 if (m_position == Dock::Position::Left || m_position == Dock::Position::Right) { showSingle = m_dockInter->windowSizeFashion() < CRITLCALHEIGHT; } // 如果是一行或者是在切换位置(从左右切换到上下) if (showSingle) { return m_trayView->suitableSize(position).width() + m_quickIconWidget->suitableSize(position).width() + m_dateTimeWidget->suitableSize(position).width() + 4; } //如果是两行 int topWidth = m_trayView->suitableSize(position).width() + m_quickIconWidget->suitableSize(position).width(); int bottomWidth = m_dateTimeWidget->suitableSize(position).width(); return qMax(topWidth, bottomWidth); } int trayHeight = m_trayView->suitableSize(position).height(); int traypluginHeight = trayHeight + m_quickIconWidget->suitableSize(position).height() + m_appPluginLayout->spacing(); return traypluginHeight + m_dateTimeWidget->suitableSize(position).height() + 10; } QSize TrayManagerWindow::suitableSize() const { return suitableSize(m_position); } QSize TrayManagerWindow::suitableSize(const Dock::Position &position) const { QMargins m = m_mainLayout->contentsMargins(); if (position == Dock::Position::Top || position == Dock::Position::Bottom) { return QSize(appDatetimeSize(position) + m_systemPluginWidget->suitableSize(position).width() + m_mainLayout->spacing() + m.left() + m.right(), QWIDGETSIZE_MAX); } return QSize(QWIDGETSIZE_MAX, appDatetimeSize(position) + m_systemPluginWidget->suitableSize(position).height() + m_mainLayout->spacing() + m.top() + m.bottom()); } // 用于返回需要绘制的圆形区域 QPainterPath TrayManagerWindow::roundedPaths() { QMargins mainMargin = m_mainLayout->contentsMargins(); int radius = m_borderRadius - mainMargin.top(); QPainterPath path; if ((m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) && m_singleShow) { // 如果是上下方向,且只有一行 // 计算托盘和快捷插件区域 QPoint pointPlugin(mainMargin.left(), mainMargin.top()); QRect rctPlugin(QPoint(mainMargin.left(), mainMargin.top()), m_appPluginWidget->size()); path.addRoundedRect(rctPlugin, radius, radius); // 计算日期时间区域 QPoint pointDateTime = m_dateTimeWidget->pos(); pointDateTime = m_dateTimeWidget->parentWidget()->mapTo(this, pointDateTime); QRect rctDatetime(pointDateTime, m_dateTimeWidget->size()); path.addRoundedRect(rctDatetime, radius, radius); // 计算系统插件区域 path.addRoundedRect(m_systemPluginWidget->geometry(), radius, radius); } else { // 添加系统插件区域的位置信息 path.addRoundedRect(m_appPluginDatetimeWidget->geometry(), radius, radius); path.addRoundedRect(m_systemPluginWidget->geometry(), radius, radius); } return path; } void TrayManagerWindow::onTrayCountChanged() { resetChildWidgetSize(); Q_EMIT requestUpdate(); } void TrayManagerWindow::onRequestUpdateWidget(const QList &idxs) { for (int i = 0; i < idxs.size(); i++) { int idx = idxs[i]; if (idx < m_model->rowCount()) { QModelIndex index = m_model->index(idx); m_trayView->closePersistentEditor(index); m_trayView->openPersistentEditor(index); } } } void TrayManagerWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); updateLayout(); } void TrayManagerWindow::initUi() { m_systemPluginWidget->setDisplayMode(Dock::DisplayMode::Fashion); m_trayView->setModel(m_model); m_trayView->setItemDelegate(m_delegate); m_trayView->setDragDistance(2); m_splitLine->setFixedHeight(1); QPalette pal; QColor lineColor(Qt::black); lineColor.setAlpha(static_cast(255 * 0.1)); pal.setColor(QPalette::Background, lineColor); m_splitLine->setAutoFillBackground(true); m_splitLine->setPalette(pal); // 左侧的区域,包括应用托盘插件和下方的日期时间区域 m_appPluginLayout->setContentsMargins(0, 0, 0, 0); m_appPluginLayout->setSpacing(0); m_appPluginWidget->setLayout(m_appPluginLayout); m_appPluginLayout->addWidget(m_trayView); m_appPluginLayout->addWidget(m_quickIconWidget); setLayout(m_mainLayout); // 通用情况下,设置边距和间距都为7 m_mainLayout->setContentsMargins(CONTENTSPACE, CONTENTSPACE, CONTENTSPACE, CONTENTSPACE); m_mainLayout->setSpacing(CONTENTSPACE); m_mainLayout->addWidget(m_appPluginDatetimeWidget); m_mainLayout->addWidget(m_systemPluginWidget); } void TrayManagerWindow::initConnection() { connect(m_trayView, &TrayGridView::requestRemove, m_model, &TrayModel::removeRow); connect(m_model, &TrayModel::rowCountChanged, this, &TrayManagerWindow::onTrayCountChanged); connect(m_model, &TrayModel::rowCountChanged, m_trayView, &TrayGridView::onUpdateEditorView); connect(m_model, &TrayModel::requestRefreshEditor, m_trayView, &TrayGridView::onUpdateEditorView); connect(m_quickIconWidget, &QuickPluginWindow::itemCountChanged, this, [ this ] { // 当插件数量发生变化的时候,需要调整尺寸 m_quickIconWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) m_quickIconWidget->setFixedWidth(m_quickIconWidget->suitableSize().width()); else m_quickIconWidget->setFixedHeight(m_quickIconWidget->suitableSize().height()); Q_EMIT requestUpdate(); }); connect(m_systemPluginWidget, &SystemPluginWindow::itemChanged, this, [ this ] { // 当系统插件发生变化的时候,同样需要调整尺寸 m_systemPluginWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) m_systemPluginWidget->setFixedWidth(m_systemPluginWidget->suitableSize().width()); else m_systemPluginWidget->setFixedHeight(m_systemPluginWidget->suitableSize().height()); Q_EMIT requestUpdate(); }); connect(m_trayView, &TrayGridView::dragLeaved, m_delegate, [ this ]{ Q_EMIT m_delegate->requestDrag(true); }); connect(m_trayView, &TrayGridView::dragEntered, m_delegate, [ this ]{ Q_EMIT m_delegate->requestDrag(false); }); connect(m_model, &TrayModel::requestUpdateWidget, this, &TrayManagerWindow::onRequestUpdateWidget); connect(m_dateTimeWidget, &DateTimeDisplayer::requestUpdate, this, &TrayManagerWindow::requestUpdate); m_trayView->installEventFilter(this); m_quickIconWidget->installEventFilter(this); installEventFilter(this); QMetaObject::invokeMethod(this, &TrayManagerWindow::requestUpdate, Qt::QueuedConnection); } void TrayManagerWindow::resetChildWidgetSize() { int count = 0; for (int i = 0; i < m_model->rowCount(); i++) { if (!m_trayView->isRowHidden(i)) count++; } switch (m_position) { case Dock::Position::Top: case Dock::Position::Bottom: { int trayWidth = m_trayView->suitableSize().width(); int appDateTimeWidth = appDatetimeSize(m_position); QMargins m = m_appPluginLayout->contentsMargins(); if (m_singleShow) { // 单行显示 int trayHeight = m_appPluginDatetimeWidget->height() - m.top() - m.bottom(); m_trayView->setFixedSize(trayWidth, trayHeight); m_quickIconWidget->setFixedSize(m_quickIconWidget->suitableSize().width(), trayHeight); m_appPluginWidget->setFixedSize(trayWidth + m_quickIconWidget->suitableSize().width(), trayHeight); m_dateTimeWidget->setFixedSize(m_dateTimeWidget->suitableSize().width(), trayHeight); // 设置右侧的电源按钮的尺寸 m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize()); // 如果顶层窗体的高度为0,则直接让其间距为0,否则就会出现隐藏模式下,有8个像素的高度依然显示 int space = topLevelWidget()->height() == 0 ? 0 : 4; m_mainLayout->setContentsMargins(space, space, space ,space); m_mainLayout->setSpacing(space); // 单行显示需要重新设置插件和时间日期的位置,不显示分割线 m_splitLine->setVisible(false); m_appPluginWidget->move(0, 0); m_dateTimeWidget->move(m_appPluginWidget->x() + m_appPluginWidget->width() + 4, m_appPluginWidget->y()); } else { // 多行显示 m_quickIconWidget->setFixedSize(m_quickIconWidget->suitableSize()); int trayHeight = m_appPluginDatetimeWidget->height() / 2 + 4 - m.top() - m.bottom(); m_trayView->setFixedSize(trayWidth, trayHeight); m_appPluginWidget->setFixedSize(trayWidth + m_quickIconWidget->suitableSize().width(), trayHeight); // 因为是两行,所以对于时间控件的尺寸,只能设置最小值 int dateTimeWidth = qMax(m_appPluginWidget->width(), m_dateTimeWidget->suitableSize().width()); int dateTimeHeight = m_appPluginDatetimeWidget->height() - - m.top() - m.bottom() - trayHeight; m_dateTimeWidget->setFixedSize(dateTimeWidth, dateTimeHeight); m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize()); int contentSpace = qMin(MAXDIFF, qMax(height() - MINHIGHT, 0)) + MINSPACE; m_mainLayout->setContentsMargins(contentSpace, contentSpace, contentSpace, contentSpace); m_mainLayout->setSpacing(contentSpace); // 调整插件和日期窗体的位置显示,这里没有用到布局,是因为在调整任务栏位置的时候, // 随着布局方向的改变,显示有很大的问题 m_splitLine->setFixedWidth(appDateTimeWidth); m_splitLine->setVisible(true); if (m_position == Dock::Position::Bottom) { m_appPluginWidget->move(0, 0); m_splitLine->move(0, m_appPluginWidget->y() + m_appPluginWidget->height()); m_dateTimeWidget->move(0, m_appPluginWidget->y() + m_appPluginWidget->height() + m_splitLine->height()); } else { m_dateTimeWidget->move(0, 0); m_splitLine->move(0, m_dateTimeWidget->y() + m_dateTimeWidget->height()); m_appPluginWidget->move(0, m_dateTimeWidget->y() + m_dateTimeWidget->height() + m_splitLine->height()); } } QMargins margin = m_mainLayout->contentsMargins(); int appDateHeight = height() - margin.top() - margin.bottom(); m_appPluginDatetimeWidget->setFixedSize(appDateTimeWidth, appDateHeight); break; } case Dock::Position::Left: case Dock::Position::Right: { int trayHeight = m_trayView->suitableSize().height(); int quickAreaHeight = m_quickIconWidget->suitableSize().height(); QMargins m = m_appPluginLayout->contentsMargins(); // 左右方向始终只有一列 int datetimeHeight = m_dateTimeWidget->suitableSize().height(); int sizeWidth = m_appPluginDatetimeWidget->width() - m.left() - m.right(); m_trayView->setFixedSize(sizeWidth, trayHeight); m_quickIconWidget->setFixedSize(sizeWidth, quickAreaHeight); m_dateTimeWidget->setFixedSize(sizeWidth, datetimeHeight); m_appPluginWidget->setFixedSize(sizeWidth, trayHeight + quickAreaHeight); m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize()); int contentSpace = (qMin(MAXDIFF, qMax(width() - MINHIGHT, 0)) + MINSPACE); m_mainLayout->setContentsMargins(contentSpace, contentSpace, contentSpace, contentSpace); m_mainLayout->setSpacing(contentSpace); int appDateWidth = width() - (contentSpace * 2); m_appPluginDatetimeWidget->setFixedSize(appDateWidth, appDatetimeSize(m_position)); // 调整各个部件的位置 m_appPluginWidget->move(0, 0); m_splitLine->setFixedWidth(width()); m_splitLine->setVisible(true); m_splitLine->move(0, m_appPluginWidget->y() + m_appPluginWidget->height()); m_dateTimeWidget->move(0, m_appPluginWidget->y() + m_appPluginWidget->height() + m_splitLine->height()); break; } } } void TrayManagerWindow::resetSingleDirection() { switch (m_position) { case Dock::Position::Top: case Dock::Position::Bottom: { m_appPluginLayout->setDirection(QBoxLayout::Direction::LeftToRight); // 应用和时间在一行显示 m_mainLayout->setDirection(QBoxLayout::Direction::LeftToRight); m_splitLine->hide(); break; } case Dock::Position::Left: case Dock::Position::Right:{ m_appPluginLayout->setDirection(QBoxLayout::Direction::TopToBottom); m_mainLayout->setDirection(QBoxLayout::Direction::TopToBottom); m_splitLine->show(); break; } } m_dateTimeWidget->setOneRow(true); } void TrayManagerWindow::resetMultiDirection() { switch (m_position) { case Dock::Position::Top: case Dock::Position::Bottom: { m_appPluginLayout->setDirection(QBoxLayout::Direction::LeftToRight); m_mainLayout->setDirection(QBoxLayout::Direction::LeftToRight); m_splitLine->show(); m_dateTimeWidget->setOneRow(false); break; } case Dock::Position::Left: case Dock::Position::Right: { m_appPluginLayout->setDirection(QBoxLayout::Direction::TopToBottom); m_mainLayout->setDirection(QBoxLayout::Direction::TopToBottom); m_splitLine->hide(); m_dateTimeWidget->setOneRow(true); break; } } } void TrayManagerWindow::dragEnterEvent(QDragEnterEvent *e) { e->setDropAction(Qt::CopyAction); e->accept(); } void TrayManagerWindow::dragMoveEvent(QDragMoveEvent *e) { e->setDropAction(Qt::CopyAction); e->accept(); } void TrayManagerWindow::dropEvent(QDropEvent *e) { if (!e || !e->mimeData() || e->source() == this) return; if (qobject_cast(e->source())) { const QuickPluginMimeData *mimeData = qobject_cast(e->mimeData()); if (!mimeData) return; PluginsItemInterface *pluginItem = static_cast(mimeData->pluginItemInterface()); if (pluginItem) m_quickIconWidget->dragPlugin(pluginItem); } else if (qobject_cast(e->source())) { // 将trayView中的dropEvent扩大到整个区域(this),这样便于随意拖动到这个区域都可以捕获。 // m_trayView中有e->accept不会导致事件重复处理。 m_trayView->handleDropEvent(e); } } void TrayManagerWindow::dragLeaveEvent(QDragLeaveEvent *event) { event->accept(); } void TrayManagerWindow::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainterPath path = roundedPaths(); QPainter painter(this); painter.save(); painter.setRenderHint(QPainter::Antialiasing); painter.setClipPath(path); painter.fillRect(rect().adjusted(1, 1, -1, -1), maskColor(102)); painter.setPen(maskColor(110)); painter.drawPath(path); painter.restore(); } QColor TrayManagerWindow::maskColor(uint8_t alpha) const { QColor color = DGuiApplicationHelper::standardPalette(DGuiApplicationHelper::instance()->themeType()).window().color(); color.setAlpha(alpha); return color; }