/* * 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 "quicksettingcontainer.h" #include "brightnessmodel.h" #include "quicksettingcontroller.h" #include "pluginsiteminterface.h" #include "quicksettingitem.h" #include "mediawidget.h" #include "dockpopupwindow.h" #include "brightnesswidget.h" #include "slidercontainer.h" #include "volumewidget.h" #include "volumedeviceswidget.h" #include "pluginchildpage.h" #include "volumemodel.h" #include "utils.h" #include "displaysettingwidget.h" #include #include #include #include #include #include #include DWIDGET_USE_NAMESPACE struct QuickDragInfo { QPoint dragPosition; QuickSettingItem *dragItem = nullptr; void reset() { dragPosition.setX(0); dragPosition.setY(0); dragItem = nullptr; } bool isNull() { return !dragItem; } } QuickDragInfo; #define ITEMWIDTH 70 #define ITEMHEIGHT 60 #define ITEMSPACE 10 #define COLUMNCOUNT 4 DockPopupWindow *QuickSettingContainer::m_popWindow = nullptr; Dock::Position QuickSettingContainer::m_position = Dock::Position::Bottom; QuickSettingContainer::QuickSettingContainer(QWidget *parent) : QWidget(parent) , m_switchLayout(new QStackedLayout(this)) , m_mainWidget(new QWidget(this)) , m_pluginWidget(new QWidget(m_mainWidget)) , m_pluginLayout(new QGridLayout(m_pluginWidget)) , m_componentWidget(new QWidget(m_mainWidget)) , m_mainlayout(new QVBoxLayout(m_mainWidget)) , m_pluginLoader(QuickSettingController::instance()) , m_playerWidget(new MediaWidget(m_componentWidget)) , m_volumeModel(new VolumeModel(this)) , m_brightnessModel(new BrightnessModel(this)) , m_volumnWidget(new VolumeWidget(m_volumeModel, m_componentWidget)) , m_brihtnessWidget(new BrightnessWidget(m_brightnessModel, m_componentWidget)) , m_volumeSettingWidget(new VolumeDevicesWidget(m_volumeModel, this)) , m_displaySettingWidget(new DisplaySettingWidget(this)) , m_childPage(new PluginChildPage(this)) , m_dragInfo(new struct QuickDragInfo) { initUi(); initConnection(); m_childPage->installEventFilter(this); setMouseTracking(true); } QuickSettingContainer::~QuickSettingContainer() { delete m_dragInfo; } void QuickSettingContainer::showHomePage() { m_switchLayout->setCurrentIndex(0); } // 根据位置获取箭头的方向 static DArrowRectangle::ArrowDirection getDirection(const Dock::Position &position) { switch (position) { case Dock::Position::Top: return DArrowRectangle::ArrowDirection::ArrowTop; case Dock::Position::Left: return DArrowRectangle::ArrowDirection::ArrowLeft; case Dock::Position::Right: return DArrowRectangle::ArrowDirection::ArrowRight; default: return DArrowRectangle::ArrowDirection::ArrowBottom; } return DArrowRectangle::ArrowDirection::ArrowBottom; } DockPopupWindow *QuickSettingContainer::popWindow() { if (m_popWindow) { QuickSettingContainer *container = static_cast(m_popWindow->getContent()); container->showHomePage(); return m_popWindow; } m_popWindow = new DockPopupWindow; m_popWindow->setWindowFlag(Qt::Popup); m_popWindow->setShadowBlurRadius(20); m_popWindow->setRadius(18); m_popWindow->setShadowYOffset(2); m_popWindow->setShadowXOffset(0); m_popWindow->setArrowWidth(18); m_popWindow->setArrowHeight(10); m_popWindow->setArrowDirection(getDirection(m_position)); m_popWindow->setContent(new QuickSettingContainer(m_popWindow)); if (Utils::IS_WAYLAND_DISPLAY) m_popWindow->setWindowFlags(m_popWindow->windowFlags() | Qt::FramelessWindowHint | Qt::Popup); return m_popWindow; } void QuickSettingContainer::setPosition(Position position) { if (m_position == position) return; m_position = position; if (m_popWindow) { m_popWindow->setArrowDirection(getDirection(m_position)); // 在任务栏位置发生变化的时候,需要将当前的content获取后,重新调用setContent接口 // 如果不调用,那么就会出现内容在容器内部的位置错误,界面上的布局会乱 QWidget *widget = m_popWindow->getContent(); m_popWindow->setContent(widget); } } void QuickSettingContainer::initQuickItem(PluginsItemInterface *plugin) { QuickSettingItem *quickItem = new QuickSettingItem(plugin, m_pluginLoader->itemKey(plugin), m_pluginLoader->metaData(plugin)); quickItem->setParent(m_pluginWidget); quickItem->setMouseTracking(true); quickItem->installEventFilter(this); connect(quickItem, &QuickSettingItem::detailClicked, this, &QuickSettingContainer::onItemDetailClick); m_quickSettings << quickItem; } void QuickSettingContainer::onItemDetailClick(PluginsItemInterface *pluginInter) { QuickSettingItem *quickItemWidget = static_cast(sender()); if (!quickItemWidget) return; QWidget *widget = pluginInter->itemPopupApplet(QUICK_ITEM_DETAIL_KEY); if (!widget) return; showWidget(widget, pluginInter->pluginDisplayName()); onResizeView(); } bool QuickSettingContainer::eventFilter(QObject *watched, QEvent *event) { switch (event->type()) { case QEvent::Resize: { if (watched == m_childPage) onResizeView(); break; } case QEvent::MouseButtonPress: { QuickSettingItem *item = qobject_cast(watched); if (!item) break; QMouseEvent *mouseEvent = static_cast(event); m_dragInfo->dragPosition = mouseEvent->pos(); m_dragInfo->dragItem = item; break; } case QEvent::MouseButtonRelease: { m_dragInfo->reset(); break; } default: break; } return QWidget::eventFilter(watched, event); } void QuickSettingContainer::showWidget(QWidget *widget, const QString &title) { m_childPage->setTitle(title); m_childPage->pushWidget(widget); m_switchLayout->setCurrentWidget(m_childPage); } QPoint QuickSettingContainer::hotSpot(const QPixmap &pixmap) { if (m_position == Dock::Position::Left) return QPoint(0, pixmap.height()); if (m_position == Dock::Position::Top) return QPoint(pixmap.width(), 0); return QPoint(pixmap.width(), pixmap.height()); } void QuickSettingContainer::onPluginInsert(PluginsItemInterface * itemInter) { initQuickItem(itemInter); updateItemLayout(); onResizeView(); } void QuickSettingContainer::onPluginRemove(PluginsItemInterface * itemInter) { QuickSettingItem *quickItem = nullptr; for (QuickSettingItem *settingItem : m_quickSettings) { if (settingItem->pluginItem() != itemInter) continue; quickItem = settingItem; break; } if (!quickItem) return; m_pluginLayout->removeWidget(quickItem); m_quickSettings.removeOne(quickItem); disconnect(quickItem, &QuickSettingItem::detailClicked, this, &QuickSettingContainer::onItemDetailClick); quickItem->setParent(nullptr); quickItem->removeEventFilter(this); quickItem->setMouseTracking(false); quickItem->deleteLater(); //调整子控件的位置 updateItemLayout(); onResizeView(); } void QuickSettingContainer::mouseMoveEvent(QMouseEvent *event) { if (m_dragInfo->isNull()) return; QPoint pointCurrent = event->pos(); if (qAbs(m_dragInfo->dragPosition.x() - pointCurrent.x()) > 5 || qAbs(m_dragInfo->dragPosition.y() - pointCurrent.y()) > 5) { QuickSettingItem *moveItem = m_dragInfo->dragItem; m_dragInfo->reset(); QDrag *drag = new QDrag(this); QuickPluginMimeData *mimedata = new QuickPluginMimeData(moveItem->pluginItem()); drag->setMimeData(mimedata); QPixmap dragPixmap = moveItem->dragPixmap(); drag->setPixmap(dragPixmap); drag->setHotSpot(hotSpot(dragPixmap)); drag->exec(Qt::MoveAction | Qt::CopyAction); } } void QuickSettingContainer::updateItemLayout() { // 清空之前的控件,重新添加 while (m_pluginLayout->count() > 0) m_pluginLayout->takeAt(0); int row = 0; int column = 0; for (QuickSettingItem *item : m_quickSettings) { int usedColumn = item->isPrimary() ? 2 : 1; m_pluginLayout->addWidget(item, row, column, 1, usedColumn); column += usedColumn; if (column >= COLUMNCOUNT) { row++; column = 0; } } } void QuickSettingContainer::initUi() { auto setWidgetStyle = [](DBlurEffectWidget *widget) { widget->setMaskColor(QColor(239, 240, 245)); widget->setBlurRectXRadius(8); widget->setBlurRectYRadius(8); }; // 添加音乐播放插件 m_playerWidget->setFixedHeight(ITEMHEIGHT); m_volumnWidget->setFixedHeight(ITEMHEIGHT); m_brihtnessWidget->setFixedHeight(ITEMHEIGHT); setWidgetStyle(m_playerWidget); setWidgetStyle(m_volumnWidget); setWidgetStyle(m_brihtnessWidget); m_mainlayout->setSpacing(ITEMSPACE); m_mainlayout->setContentsMargins(ITEMSPACE, ITEMSPACE, ITEMSPACE, ITEMSPACE); m_pluginLayout->setContentsMargins(0, 0, 0, 0); m_pluginLayout->setSpacing(ITEMSPACE); m_pluginLayout->setAlignment(Qt::AlignLeft); for (int i = 0; i < COLUMNCOUNT; i++) m_pluginLayout->setColumnMinimumWidth(i, ITEMWIDTH); m_pluginWidget->setLayout(m_pluginLayout); m_mainlayout->addWidget(m_pluginWidget); QVBoxLayout *ctrlLayout = new QVBoxLayout(m_componentWidget); ctrlLayout->setContentsMargins(0, 0, 0, 0); ctrlLayout->setSpacing(ITEMSPACE); ctrlLayout->addWidget(m_playerWidget); ctrlLayout->addWidget(m_volumnWidget); ctrlLayout->addWidget(m_brihtnessWidget); m_mainlayout->addWidget(m_componentWidget); // 加载所有的插件 QList plugins = m_pluginLoader->pluginItems(QuickSettingController::PluginAttribute::Quick); for (PluginsItemInterface *plugin : plugins) initQuickItem(plugin); m_switchLayout->addWidget(m_mainWidget); m_switchLayout->addWidget(m_childPage); m_volumeSettingWidget->hide(); setMouseTracking(true); setAcceptDrops(true); QMetaObject::invokeMethod(this, [ = ] { if (plugins.size() > 0) updateItemLayout(); // 设置当前窗口的大小 onResizeView(); setFixedWidth(ITEMWIDTH * 4 + (ITEMSPACE * 5)); }, Qt::QueuedConnection); m_displaySettingWidget->setVisible(false); } void QuickSettingContainer::initConnection() { connect(m_pluginLoader, &QuickSettingController::pluginInserted, this, [ = ](PluginsItemInterface *itemInter, const QuickSettingController::PluginAttribute &pluginClass) { if (pluginClass != QuickSettingController::PluginAttribute::Quick) return; onPluginInsert(itemInter); }); connect(m_pluginLoader, &QuickSettingController::pluginRemoved, this, &QuickSettingContainer::onPluginRemove); connect(m_playerWidget, &MediaWidget::visibleChanged, this, &QuickSettingContainer::onResizeView); connect(m_volumnWidget, &VolumeWidget::visibleChanged, this, &QuickSettingContainer::onResizeView); connect(m_volumnWidget, &VolumeWidget::rightIconClick, this, [ this ] { showWidget(m_volumeSettingWidget, tr("voice")); onResizeView(); }); connect(m_brihtnessWidget, &BrightnessWidget::visibleChanged, this, &QuickSettingContainer::onResizeView); connect(m_brihtnessWidget->sliderContainer(), &SliderContainer::iconClicked, this, [ this ](const SliderContainer::IconPosition &iconPosition) { if (iconPosition == SliderContainer::RightIcon) { // 点击右侧的按钮,弹出具体的调节的界面 showWidget(m_displaySettingWidget, tr("brightness")); onResizeView(); } }); connect(m_childPage, &PluginChildPage::back, this, [ this ] { m_switchLayout->setCurrentWidget(m_mainWidget); }); connect(m_childPage, &PluginChildPage::closeSelf, this, [ this ] { if (!m_childPage->isBack()) topLevelWidget()->hide(); }); } // 调整尺寸 void QuickSettingContainer::onResizeView() { if (m_switchLayout->currentWidget() == m_mainWidget) { int selfPluginCount = 0; for (QuickSettingItem *item : m_quickSettings) { // 如果是置顶的插件,则认为它占用两个普通插件的位置 int increCount = (item->isPrimary() ? 2 : 1); selfPluginCount += increCount; } int rowCount = selfPluginCount / COLUMNCOUNT; if (selfPluginCount % COLUMNCOUNT > 0) rowCount++; m_pluginWidget->setFixedHeight(ITEMHEIGHT * rowCount + ITEMSPACE * (rowCount - 1)); int panelCount = 0; if (m_playerWidget->isVisible()) panelCount++; if (m_volumnWidget->isVisible()) panelCount++; if (m_brihtnessWidget->isVisible()) panelCount++; m_componentWidget->setFixedHeight(ITEMHEIGHT * panelCount + ITEMSPACE * (panelCount - 1)); setFixedHeight(ITEMSPACE * 3 + m_pluginWidget->height() + m_componentWidget->height()); } else if (m_switchLayout->currentWidget() == m_childPage) { setFixedHeight(m_childPage->height()); } }