diff --git a/plugins/display/CMakeLists.txt b/plugins/display/CMakeLists.txt new file mode 100644 index 000000000..a727f2557 --- /dev/null +++ b/plugins/display/CMakeLists.txt @@ -0,0 +1,51 @@ + +set(PLUGIN_NAME "display") + +project(${PLUGIN_NAME}) + +generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface) + +# Sources files +file(GLOB_RECURSE SRCS "*.h" "*.cpp" + "../../widgets/*.h" + "../../widgets/*.cpp" + "../../frame/util/imageutil.h" + "../../frame/util/imageutil.cpp" + "../../frame/util/statebutton.h" + "../../frame/util/statebutton.cpp" + "../../frame/util/horizontalseperator.h" + "../../frame/util/horizontalseperator.cpp" + "../../frame/qtdbusextended/*.h" + "../../frame/qtdbusextended/*.cpp") + +find_package(PkgConfig REQUIRED) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5Svg REQUIRED) +find_package(Qt5DBus REQUIRED) +find_package(DtkWidget REQUIRED) + +pkg_check_modules(XCB_EWMH REQUIRED xcb-ewmh x11 xcursor) +pkg_check_modules(QGSettings REQUIRED gsettings-qt) + +add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN") +add_library(${PLUGIN_NAME} SHARED ${SRCS} ./resource/display.qrc) +set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../quick-trays) +target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS} + ${QGSettings_INCLUDE_DIRS} + ../../interfaces + ../../widgets + ../../frame + ../../frame/qtdbusextended + ./dbusinterface/generation_dbus_interface + componments) + +target_link_libraries(${PLUGIN_NAME} PRIVATE + ${XCB_EWMH_LIBRARIES} + ${DtkWidget_LIBRARIES} + ${QGSettings_LIBRARIES} + ${Qt5DBus_LIBRARIES} + ${Qt5Widgets_LIBRARIES} + ${Qt5Svg_LIBRARIES} +) + +install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins/quick-trays) diff --git a/plugins/display/brightnessadjwidget.cpp b/plugins/display/brightnessadjwidget.cpp new file mode 100644 index 000000000..1b339a977 --- /dev/null +++ b/plugins/display/brightnessadjwidget.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 "brightnessadjwidget.h" +#include "brightnessmodel.h" +#include "slidercontainer.h" +#include "imageutil.h" + +#include + +const int ItemSpacing = 5; + +BrightnessAdjWidget::BrightnessAdjWidget(QWidget *parent) + : QWidget(parent) + , m_mainLayout(new QVBoxLayout(this)) + , m_brightnessModel(new BrightnessModel(this)) +{ + m_mainLayout->setMargin(0); + m_mainLayout->setSpacing(ItemSpacing); + + loadBrightnessItem(); +} + +void BrightnessAdjWidget::loadBrightnessItem() +{ + QList monitors = m_brightnessModel->monitors(); + int itemHeight = monitors.count() > 1 ? 56 : 30; + + for (BrightMonitor *monitor : monitors) { + SliderContainer *sliderContainer = new SliderContainer(this); + if (monitors.count() > 1) + sliderContainer->setTitle(monitor->name()); + + QPixmap leftPixmap = ImageUtil::loadSvg(":/icons/resources/brightnesslow", QSize(20, 20)); + QPixmap rightPixmap = ImageUtil::loadSvg(":/icons/resources/brightnesshigh", QSize(20, 20)); + sliderContainer->setIcon(SliderContainer::IconPosition::LeftIcon,leftPixmap, QSize(), 12); + sliderContainer->setIcon(SliderContainer::IconPosition::RightIcon, rightPixmap, QSize(), 12); + + sliderContainer->setFixedWidth(310); + sliderContainer->setFixedHeight(itemHeight); + sliderContainer->updateSliderValue(monitor->brightness()); + + SliderProxyStyle *proxy = new SliderProxyStyle(SliderProxyStyle::Normal); + sliderContainer->setSliderProxyStyle(proxy); + m_mainLayout->addWidget(sliderContainer); + + connect(monitor, &BrightMonitor::brightnessChanged, sliderContainer, &SliderContainer::updateSliderValue); + connect(sliderContainer, &SliderContainer::sliderValueChanged, monitor, &BrightMonitor::setBrightness); + } + + QMargins margins = this->contentsMargins(); + setFixedHeight(margins.top() + margins.bottom() + monitors.count() * itemHeight + monitors.count() * ItemSpacing); +} + diff --git a/plugins/display/brightnessadjwidget.h b/plugins/display/brightnessadjwidget.h new file mode 100644 index 000000000..74482c7d8 --- /dev/null +++ b/plugins/display/brightnessadjwidget.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 . + */ +#ifndef BRIGHTNESS_ADJUSTMENT_WIDGET_H +#define BRIGHTNESS_ADJUSTMENT_WIDGET_H + +#include + +class QVBoxLayout; +class BrightnessModel; + +/*! + * \brief The BrightnessAdjWidget class + * 显示器亮度调整页面 + */ +class BrightnessAdjWidget : public QWidget +{ + Q_OBJECT +public: + explicit BrightnessAdjWidget(QWidget *parent = nullptr); + +private: + void loadBrightnessItem(); + +private: + QVBoxLayout *m_mainLayout; + BrightnessModel *m_brightnessModel; +}; + + +#endif // BRIGHTNESS_ADJUSTMENT_WIDGET_H diff --git a/plugins/display/brightnessmodel.cpp b/plugins/display/brightnessmodel.cpp new file mode 100644 index 000000000..e7c024bce --- /dev/null +++ b/plugins/display/brightnessmodel.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: sbw + * kirigaya + * Hualet + * + * Maintainer: sbw + * kirigaya + * Hualet + * + * 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 "brightnessmodel.h" + +#include +#include +#include +#include +#include +#include + +static const QString serviceName("com.deepin.daemon.Display"); +static const QString servicePath("/com/deepin/daemon/Display"); +static const QString serviceInterface("com.deepin.daemon.Display"); +static const QString propertiesInterface("org.freedesktop.DBus.Properties"); + +BrightnessModel::BrightnessModel(QObject *parent) + : QObject(parent) +{ + QDBusInterface dbusInter(serviceName, servicePath, serviceInterface, QDBusConnection::sessionBus()); + if (dbusInter.isValid()) { + // 读取所有的屏幕的信息 + QString primaryScreenName = dbusInter.property("Primary").value(); + QList paths = dbusInter.property("Monitors").value>(); + for (QDBusObjectPath path : paths) { + BrightMonitor *monitor = new BrightMonitor(path.path(), this); + monitor->setPrimary(primaryScreenName == monitor->name()); + m_monitor << monitor; + } + } + + connect(qApp, &QApplication::primaryScreenChanged, this, &BrightnessModel::primaryScreenChanged); +} + +BrightnessModel::~BrightnessModel() +{ +} + +QList BrightnessModel::monitors() +{ + return m_monitor; +} + +BrightMonitor *BrightnessModel::primaryMonitor() const +{ + for (BrightMonitor *monitor : m_monitor) { + if (monitor->isPrimary()) + return monitor; + } + + return nullptr; +} + +void BrightnessModel::primaryScreenChanged(QScreen *screen) +{ + BrightMonitor *defaultMonitor = nullptr; + for (BrightMonitor *monitor : m_monitor) { + monitor->setPrimary(monitor->name() == screen->name()); + if (monitor->isPrimary()) + defaultMonitor = monitor; + } + + if (defaultMonitor) + Q_EMIT primaryChanged(defaultMonitor); +} + +/** + * @brief monitor + */ +BrightMonitor::BrightMonitor(QString path, QObject *parent) + : QObject(parent) + , m_path(path) + , m_brightness(100) + , m_enabled(false) + , m_isPrimary(false) +{ + QDBusInterface dbusInter(serviceName, path, serviceInterface + QString(".Monitor"), QDBusConnection::sessionBus()); + if (dbusInter.isValid()) { + // 读取所有的屏幕的信息 + m_name = dbusInter.property("Name").toString(); + m_brightness = static_cast(dbusInter.property("Brightness").toDouble() * 100); + m_enabled = dbusInter.property("Enabled").toBool(); + } + + QDBusConnection::sessionBus().connect(serviceName, path, propertiesInterface, + "PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &))); +} + +BrightMonitor::~BrightMonitor() +{ +} + +void BrightMonitor::setPrimary(bool primary) +{ + m_isPrimary = primary; +} + +int BrightMonitor::brightness() +{ + return m_brightness; +} + +bool BrightMonitor::enabled() +{ + return m_enabled; +} + +QString BrightMonitor::name() +{ + return m_name; +} + +bool BrightMonitor::isPrimary() +{ + return m_isPrimary; +} + +void BrightMonitor::setBrightness(int value) +{ + callMethod("SetBrightness", { m_name, static_cast(value * 0.01) }); +} + +void BrightMonitor::onPropertyChanged(const QDBusMessage &msg) +{ + QList arguments = msg.arguments(); + if (3 != arguments.count()) + return; + + QString interfaceName = msg.arguments().at(0).toString(); + if (interfaceName != QString("%1.Monitor").arg(serviceInterface)) + return; + + QVariantMap changedProps = qdbus_cast(arguments.at(1).value()); + if (changedProps.contains("Brightness")) { + int brightness = static_cast(changedProps.value("Brightness").value() * 100); + if (brightness != m_brightness) { + m_brightness = brightness; + Q_EMIT brightnessChanged(brightness); + } + } + if (changedProps.contains("Name")) { + QString name = changedProps.value("Name").value(); + if (name != m_name) { + m_name = name; + Q_EMIT nameChanged(name); + } + } + if (changedProps.contains("Enabled")) { + bool enabled = changedProps.value("Enabled").value(); + if (enabled != m_enabled) { + m_enabled = enabled; + Q_EMIT enabledChanged(enabled); + } + } +} + +QDBusMessage BrightMonitor::callMethod(const QString &methodName, const QList &argument) +{ + QDBusInterface dbusInter(serviceName, servicePath, serviceInterface, QDBusConnection::sessionBus()); + if (dbusInter.isValid()) { + QDBusPendingCall reply = dbusInter.asyncCallWithArgumentList(methodName, argument); + reply.waitForFinished(); + return reply.reply(); + } + + return QDBusMessage(); +} diff --git a/plugins/display/brightnessmodel.h b/plugins/display/brightnessmodel.h new file mode 100644 index 000000000..b9c0c022b --- /dev/null +++ b/plugins/display/brightnessmodel.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 ~ 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 . + */ + +#ifndef BRIGHTNESSMODEL_H +#define BRIGHTNESSMODEL_H + +#include + +class BrightMonitor; +class QDBusMessage; +class QScreen; + +class BrightnessModel : public QObject +{ + Q_OBJECT + +public: + explicit BrightnessModel(QObject *parent = nullptr); + ~BrightnessModel(); + + QList monitors(); + BrightMonitor *primaryMonitor() const; + +Q_SIGNALS: + void primaryChanged(BrightMonitor *); + +protected Q_SLOTS: + void primaryScreenChanged(QScreen *screen); + +private: + QList m_monitor; +}; + +class BrightMonitor : public QObject +{ + Q_OBJECT + +public: + explicit BrightMonitor(QString path, QObject *parent); + ~BrightMonitor(); + +Q_SIGNALS: + void brightnessChanged(int); + void nameChanged(QString); + void enabledChanged(bool); + +public: + void setPrimary(bool primary); + int brightness(); + bool enabled(); + QString name(); + bool isPrimary(); + +public slots: + void setBrightness(int value); + void onPropertyChanged(const QDBusMessage &msg); + +private: + QDBusMessage callMethod(const QString &methodName, const QList &argument); + +private: + QString m_path; + QString m_name; + int m_brightness; + bool m_enabled; + bool m_isPrimary; +}; + +#endif // DISPLAYMODEL_H diff --git a/plugins/display/brightnesswidget.cpp b/plugins/display/brightnesswidget.cpp new file mode 100644 index 000000000..2c148e2ac --- /dev/null +++ b/plugins/display/brightnesswidget.cpp @@ -0,0 +1,103 @@ +/* + * 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 "brightnesswidget.h" +#include "brightnessmodel.h" +#include "imageutil.h" +#include "slidercontainer.h" + +#include +#include + +#define BACKSIZE 36 +#define IMAGESIZE 18 + +BrightnessWidget::BrightnessWidget(BrightnessModel *model, QWidget *parent) + : QWidget(parent) + , m_sliderContainer(new SliderContainer(this)) + , m_model(model) +{ + initUi(); + initConnection(); +} + +BrightnessWidget::~BrightnessWidget() +{ +} + +void BrightnessWidget::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + + // 显示的时候更新一下slider的主屏幕亮度值 + updateSliderValue(); + Q_EMIT visibleChanged(true); +} + +void BrightnessWidget::hideEvent(QHideEvent *event) +{ + QWidget::hideEvent(event); + + Q_EMIT visibleChanged(true); +} + +void BrightnessWidget::initUi() +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setContentsMargins(15, 0, 12, 0); + + QPixmap leftPixmap = ImageUtil::loadSvg(":/brightness.svg", QSize(IMAGESIZE, IMAGESIZE)); + QPixmap rightPixmap = ImageUtil::loadSvg(":/ICON_Device_Laptop.svg", QSize(IMAGESIZE, IMAGESIZE)); + m_sliderContainer->setIcon(SliderContainer::IconPosition::LeftIcon, leftPixmap, QSize(), 10); + m_sliderContainer->setIcon(SliderContainer::IconPosition::RightIcon, rightPixmap, QSize(BACKSIZE, BACKSIZE), 12); + + // 需求要求调节范围是10%-100%,且调节幅度为1% + m_sliderContainer->setRange(10, 100); + m_sliderContainer->setPageStep(1); + + SliderProxyStyle *style = new SliderProxyStyle; + m_sliderContainer->setSliderProxyStyle(style); + + mainLayout->addWidget(m_sliderContainer); +} + +void BrightnessWidget::initConnection() +{ + connect(m_sliderContainer, &SliderContainer::sliderValueChanged, this, [ this ](int value) { + BrightMonitor *monitor = m_model->primaryMonitor(); + if (monitor) + monitor->setBrightness(value); + }); + + connect(m_sliderContainer, &SliderContainer::iconClicked, this, [ this ](const SliderContainer::IconPosition &position) { + if (position == SliderContainer::IconPosition::RightIcon) + Q_EMIT brightClicked(); + }); + + updateSliderValue(); +} + +void BrightnessWidget::updateSliderValue() +{ + BrightMonitor *monitor = m_model->primaryMonitor(); + if (monitor) { + m_sliderContainer->updateSliderValue(monitor->brightness()); + } +} diff --git a/plugins/display/brightnesswidget.h b/plugins/display/brightnesswidget.h new file mode 100644 index 000000000..78a4cf77d --- /dev/null +++ b/plugins/display/brightnesswidget.h @@ -0,0 +1,58 @@ +/* + * 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 . + */ +#ifndef BRIGHTNESSWIDGET_H +#define BRIGHTNESSWIDGET_H + +#include + +DWIDGET_USE_NAMESPACE + +class SliderContainer; +class BrightnessModel; +class BrightMonitor; + +class BrightnessWidget : public QWidget +{ + Q_OBJECT + +public: + explicit BrightnessWidget(BrightnessModel *model, QWidget *parent = nullptr); + ~BrightnessWidget() override; + +Q_SIGNALS: + void visibleChanged(bool); + void brightClicked(); + +protected: + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + +private: + void initUi(); + void initConnection(); + void updateSliderValue(); + +private: + SliderContainer *m_sliderContainer; + BrightnessModel *m_model; +}; + +#endif // LIGHTSETTINGWIDGET_H diff --git a/plugins/display/collaborationdevmodel.cpp b/plugins/display/collaborationdevmodel.cpp new file mode 100644 index 000000000..6305ec88a --- /dev/null +++ b/plugins/display/collaborationdevmodel.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 "collaborationdevmodel.h" + +#include +#include +#include +#include +#include +#include + +#include + +DGUI_USE_NAMESPACE +DCORE_USE_NAMESPACE + +static const QString CollaborationService = "com.deepin.Cooperation"; +static const QString CollaborationPath = "/com/deepin/Cooperation"; +static const QString CollaborationInterface = "com.deepin.Cooperation"; +static const QString ColPropertiesInterface = "org.freedesktop.DBus.Properties"; + +CollaborationDevModel::CollaborationDevModel(QObject *parent) + : QObject(parent) + , m_colDbusInter(new QDBusInterface(CollaborationService, CollaborationPath, CollaborationInterface, QDBusConnection::sessionBus(), this)) +{ + if (m_colDbusInter->isValid()) { + QList paths = m_colDbusInter->property("Machines").value>(); + for (const QDBusObjectPath& path : paths) { + CollaborationDevice *device = new CollaborationDevice(path.path(), this); + if (device->isValid()) + m_devices[path.path()] = device; + else + device->deleteLater(); + } + } else { + qWarning() << CollaborationService << " is invalid"; + } + + m_colDbusInter->connection().connect(CollaborationService, CollaborationPath, ColPropertiesInterface, + "PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(QDBusMessage))); +} + +void CollaborationDevModel::checkServiceValid() +{ + if (!m_colDbusInter->isValid()) { + for (CollaborationDevice *device : m_devices) { + device->deleteLater(); + } + m_devices.clear(); + Q_EMIT devicesChanged(); + } +} + +QList CollaborationDevModel::devices() const +{ + return m_devices.values(); +} + +void CollaborationDevModel::onPropertyChanged(const QDBusMessage &msg) +{ + QList arguments = msg.arguments(); + if (3 != arguments.count()) + return; + + QString interfaceName = msg.arguments().at(0).toString(); + if (interfaceName != CollaborationInterface) + return; + + QVariantMap changedProps = qdbus_cast(arguments.at(1).value()); + if (changedProps.contains("Machines")) { + QList paths = m_colDbusInter->property("Machines").value>(); + QStringList devPaths; + for (const QDBusObjectPath& path : paths) { + devPaths << path.path(); + } + updateDevice(devPaths); + } +} + +void CollaborationDevModel::updateDevice(const QStringList &devPaths) +{ + if (devPaths.isEmpty()) { + qDeleteAll(m_devices); + m_devices.clear(); + } else { + // 清除已不存在的设备 + QMapIterator it(m_devices); + while (it.hasNext()) { + it.next(); + if (!devPaths.contains(it.key())) { + it.value()->deleteLater(); + m_devices.remove(it.key()); + } + } + + // 添加新增设备 + for (const QString &path : devPaths) { + if (!m_devices.contains(path)) { + CollaborationDevice *device = new CollaborationDevice(path, this); + if (device->isValid()) + m_devices[path] = device; + else + device->deleteLater(); + } + } + } + + emit devicesChanged(); +} + +CollaborationDevice *CollaborationDevModel::getDevice(const QString &machinePath) +{ + return m_devices.value(machinePath, nullptr); +} + +CollaborationDevice::CollaborationDevice(const QString &devPath, QObject *parent) + : QObject(parent) + , m_path(devPath) + , m_OS(-1) + , m_isPaired(false) + , m_isCooperated(false) + , m_isValid(false) + , m_isCooperating(false) + , m_devDbusInter(new QDBusInterface(CollaborationService, devPath, CollaborationInterface + QString(".Machine"), + QDBusConnection::sessionBus(), this)) +{ + if (m_devDbusInter->isValid()) { + m_name = m_devDbusInter->property("Name").toString(); + m_OS = m_devDbusInter->property("OS").toInt(); + m_isPaired = m_devDbusInter->property("Paired").toBool(); + m_isCooperated = m_devDbusInter->property("Cooperating").toBool(); + m_uuid = m_devDbusInter->property("UUID").toString(); + m_isValid = true; + } else { + qWarning() << "CollaborationDevice devPath:" << devPath << " is invalid and get properties failed"; + } + + m_devDbusInter->connection().connect(CollaborationService, m_path, ColPropertiesInterface, "PropertiesChanged", + this, SLOT(onPropertyChanged(QDBusMessage))); +} + +bool CollaborationDevice::isValid() const +{ + return m_isValid; +} + +QString CollaborationDevice::name() const +{ + return m_name; +} + +QString CollaborationDevice::uuid() const +{ + return m_uuid; +} + +QString CollaborationDevice::machinePath() const +{ + return m_path; +} + +QString CollaborationDevice::deviceIcon() const +{ + switch (m_OS) { + case DeviceType::Android: { + if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) + return QString(":/icons/resources/ICON_Device_Headphone_dark.svg"); + + return QString(":/icons/resources/ICON_Device_Headphone.svg"); + } + default: { + if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) + return QString(":/icons/resources/ICON_Device_Laptop_dark.svg"); + + return QString(":/icons/resources/ICON_Device_Laptop.svg"); + } + } +} + +bool CollaborationDevice::isPaired() const +{ + return m_isPaired; +} + +bool CollaborationDevice::isCooperated() const +{ + return m_isCooperated; +} + +void CollaborationDevice::setDeviceIsCooperating(bool isCooperating) +{ + m_isCooperating = isCooperating; +} + +void CollaborationDevice::onPropertyChanged(const QDBusMessage &msg) +{ + QList arguments = msg.arguments(); + if (3 != arguments.count()) + return; + + QString interfaceName = msg.arguments().at(0).toString(); + if (interfaceName != QString("%1.Machine").arg(CollaborationInterface)) + return; + + QVariantMap changedProps = qdbus_cast(arguments.at(1).value()); + if (changedProps.contains("Paired")) { + bool isPaired = changedProps.value("Paired").value(); + m_isPaired = isPaired; + if (isPaired && m_isCooperating) { + // paired 成功之后再去请求cooperate + requestCooperate(); + } + + if (!isPaired){ + Q_EMIT pairedStateChanged(false); + } + } else if (changedProps.contains("Cooperating")) { + m_isCooperated = changedProps.value("Cooperating").value(); + + Q_EMIT pairedStateChanged(m_isCooperated); + } +} + +void CollaborationDevice::requestCooperate() const +{ + callMethod("RequestCooperate"); +} + +void CollaborationDevice::disconnectDevice() const +{ + callMethod("Disconnect"); +} + +void CollaborationDevice::pair() const +{ + callMethod("Pair"); +} + +QDBusMessage CollaborationDevice::callMethod(const QString &methodName) const +{ + if (m_devDbusInter->isValid()) { + QDBusMessage msg = m_devDbusInter->call(methodName); + qInfo() << "CollaborationDevice callMethod:" << methodName << " " << msg.errorMessage(); + return msg; + } + + qWarning() << "CollaborationDevice callMethod: " << methodName << " failed"; + return QDBusMessage(); +} diff --git a/plugins/display/collaborationdevmodel.h b/plugins/display/collaborationdevmodel.h new file mode 100644 index 000000000..013624211 --- /dev/null +++ b/plugins/display/collaborationdevmodel.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 . + */ +#ifndef COLLABORATION_DEV_MODEL_H +#define COLLABORATION_DEV_MODEL_H + +#include +#include + +class QTimer; +class QDBusInterface; +class QDBusMessage; +class CollaborationDevice; + +/*! + * \brief The CollaborationDevModel class + * 协同设备model + */ +class CollaborationDevModel : public QObject +{ + Q_OBJECT +public: + explicit CollaborationDevModel(QObject *parent = nullptr); + +signals: + void devicesChanged(); + +public: + void checkServiceValid(); + + QList devices() const; + CollaborationDevice *getDevice(const QString &machinePath); + +private slots: + void onPropertyChanged(const QDBusMessage &msg); + +private: + void updateDevice(const QStringList &devPaths); + +private: + QDBusInterface *m_colDbusInter; + // machine path : device object + QMap m_devices; + +}; + +/*! + * \brief The CollaborationDevice class + * 协同设备类 + */ +class CollaborationDevice : public QObject +{ + Q_OBJECT +public: + explicit CollaborationDevice(const QString &devPath, QObject *parent = nullptr); + +signals: + void pairedStateChanged(bool); + +public: + bool isValid() const; + void pair() const; + void requestCooperate() const; + void disconnectDevice() const; + + QString name() const; + QString uuid() const; + QString machinePath() const; + QString deviceIcon() const; + bool isPaired() const; + bool isCooperated() const; + void setDeviceIsCooperating(bool isCooperating); + +private slots: + void onPropertyChanged(const QDBusMessage &msg); + +private: + QDBusMessage callMethod(const QString &methodName) const; + +private: + enum DeviceType { + Other = 0, + UOS, + Linux, + Windows, + MacOS, + Android + }; + + QString m_path; + QString m_name; + QString m_uuid; + int m_OS; + + bool m_isPaired; + bool m_isCooperated; + bool m_isValid; + + // 标记任务栏点击触发协同连接 + bool m_isCooperating; + + QDBusInterface *m_devDbusInter; +}; + +#endif // COLLABORATION_DEV_MODEL_H diff --git a/plugins/display/devcollaborationwidget.cpp b/plugins/display/devcollaborationwidget.cpp new file mode 100644 index 000000000..12706a6ee --- /dev/null +++ b/plugins/display/devcollaborationwidget.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 "devcollaborationwidget.h" +#include "collaborationdevmodel.h" +#include "devitemdelegate.h" + +#include + +#include +#include +#include +#include +#include + +#define TITLE_HEIGHT 16 +#define ITEM_WIDTH 310 +#define ITEM_HEIGHT 36 +#define LISTVIEW_ITEM_SPACE 5 +#define PER_DEGREE 14 + +DevCollaborationWidget::DevCollaborationWidget(QWidget *parent) + : QWidget(parent) + , m_deviceModel(new CollaborationDevModel(this)) + , m_deviceListView(new DListView(this)) + , m_viewItemModel(new QStandardItemModel(m_deviceListView)) + , m_refreshTimer(new QTimer(this)) +{ + initUI(); + loadDevice(); + + connect(m_deviceModel, &CollaborationDevModel::devicesChanged, this, &DevCollaborationWidget::loadDevice); + connect(m_deviceListView, &DListView::clicked, this, &DevCollaborationWidget::itemClicked); + connect(m_refreshTimer, &QTimer::timeout, this, &DevCollaborationWidget::refreshViewItem); +} + +void DevCollaborationWidget::showEvent(QShowEvent *event) +{ + m_deviceModel->checkServiceValid(); + + QWidget::showEvent(event); +} + +void DevCollaborationWidget::resizeEvent(QResizeEvent *event) +{ + Q_EMIT sizeChanged(); + + QWidget::resizeEvent(event); +} + +void DevCollaborationWidget::initUI() +{ + m_deviceListView->setModel(m_viewItemModel); + + QLabel *title = new QLabel(tr("Cross-end Collaboration"), this); + title->setFixedHeight(TITLE_HEIGHT); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->setContentsMargins(10, 0, 0, 0); + hLayout->addWidget(title); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setMargin(0); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + mainLayout->addLayout(hLayout); + mainLayout->addWidget(m_deviceListView); + + setLayout(mainLayout); + + m_deviceListView->setContentsMargins(0, 0, 0, 0); + m_deviceListView->setFrameShape(QFrame::NoFrame); + m_deviceListView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_deviceListView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_deviceListView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + m_deviceListView->setResizeMode(QListView::Adjust); + m_deviceListView->setViewportMargins(0, 0, 0, 0); + m_deviceListView->setSpacing(LISTVIEW_ITEM_SPACE); + m_deviceListView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_deviceListView->setItemDelegate(new DevItemDelegate(this)); +} + +void DevCollaborationWidget::loadDevice() +{ + if (!m_deviceListView->count()) { + for (CollaborationDevice *device : m_deviceModel->devices()) { + addItem(device); + } + } else { + updateDeviceListView(); + } + + if(!m_deviceListView->count()) { + m_deviceListView->hide(); + } else { + if (!m_deviceListView->isVisible()) + m_deviceListView->setVisible(true); + + m_deviceListView->setFixedSize(ITEM_WIDTH, m_deviceListView->count() * ITEM_HEIGHT + LISTVIEW_ITEM_SPACE * (m_deviceListView->count() * 2)); + } + + resetWidgetSize(); +} + +void DevCollaborationWidget::addItem(const CollaborationDevice *device) +{ + if (!device) + return; + + QStandardItem *item = new QStandardItem(); + DevItemDelegate::DevItemData data; + data.checkedIconPath = device->deviceIcon(); // TODO + data.text = device->name(); + data.iconPath = device->deviceIcon(); + int resultState = device->isCooperated() ? DevItemDelegate::Connected : DevItemDelegate::None; + + item->setData(QVariant::fromValue(data), DevItemDelegate::StaticDataRole); + item->setData(device->machinePath(), DevItemDelegate::MachinePathDataRole); + item->setData(0, DevItemDelegate::DegreeDataRole); + item->setData(resultState, DevItemDelegate::ResultDataRole); + + m_viewItemModel->appendRow(item); + m_deviceItemMap[device->machinePath()] = item; + + connect(device, &CollaborationDevice::pairedStateChanged, this, &DevCollaborationWidget::itemStatusChanged); +} + +void DevCollaborationWidget::updateDeviceListView() +{ + QList devices = m_deviceModel->devices(); + if (devices.isEmpty()) { + m_deviceListView->removeItems(0, m_deviceListView->count()); + m_deviceItemMap.clear(); + m_connectingDevices.clear(); + return; + } + + // 删除不存在设备 + for (int row = 0; row < m_deviceListView->count(); row++) { + QStandardItem *item = m_viewItemModel->item(row); + if (!item) + continue; + + QString machinePath = item->data(DevItemDelegate::MachinePathDataRole).toString(); + if (m_deviceModel->getDevice(machinePath)) + continue; + + m_deviceListView->removeItem(row); + + if (m_deviceItemMap.contains(machinePath)) { + m_deviceItemMap.remove(machinePath); + } + + if (m_connectingDevices.contains(machinePath)) { + m_connectingDevices.removeAll(machinePath); + } + } + + // 处理新增 + for (CollaborationDevice *device : devices) { + if (!m_deviceItemMap.contains(device->machinePath())) { + addItem(device); + } + } +} + +void DevCollaborationWidget::resetWidgetSize() +{ + int height = TITLE_HEIGHT + (m_deviceListView->count() ? m_deviceListView->height() : 0); + + setFixedSize(ITEM_WIDTH, height); +} + +void DevCollaborationWidget::itemClicked(const QModelIndex &index) +{ + QString machinePath = index.data(DevItemDelegate::MachinePathDataRole).toString(); + CollaborationDevice *device = m_deviceModel->getDevice(machinePath); + if (!device) + return; + + if (!device->isPaired()) { + device->setDeviceIsCooperating(true); + device->pair(); + if (!m_connectingDevices.contains(machinePath)) + m_connectingDevices.append(machinePath); + } else if (!device->isCooperated()) { + device->requestCooperate(); + if (!m_connectingDevices.contains(machinePath)) + m_connectingDevices.append(machinePath); + } else if (device->isCooperated()) { + device->disconnectDevice(); + if (m_connectingDevices.contains(machinePath)) + m_connectingDevices.removeOne(machinePath); + } + + if (!m_connectingDevices.isEmpty() && !m_refreshTimer->isActive()) + m_refreshTimer->start(80); +} + +void DevCollaborationWidget::itemStatusChanged() +{ + CollaborationDevice *device = qobject_cast(sender()); + if (!device) + return; + + device->setDeviceIsCooperating(false); + QString machinePath = device->machinePath(); + if (m_deviceItemMap.contains(machinePath) && m_deviceItemMap[machinePath]) { + // 更新item的连接状态 + int resultState = device->isCooperated() ? DevItemDelegate::Connected : DevItemDelegate::None; + m_deviceItemMap[machinePath]->setData(resultState, DevItemDelegate::ResultDataRole); + if (device->isCooperated() || !device->isPaired()) + m_deviceItemMap[machinePath]->setData(0, DevItemDelegate::DegreeDataRole); + + m_deviceListView->update(m_deviceItemMap[machinePath]->index()); + + if ((resultState == DevItemDelegate::Connected || !device->isPaired()) && m_connectingDevices.contains(machinePath)) { + m_connectingDevices.removeAll(machinePath); + } + } +} + +void DevCollaborationWidget::refreshViewItem() +{ + if (m_connectingDevices.isEmpty()) { + m_refreshTimer->stop(); + return; + } + + for (const QString &machinePath : m_connectingDevices) { + if (m_deviceItemMap.contains(machinePath) && m_deviceItemMap[machinePath]) { + int degree = m_deviceItemMap[machinePath]->data(DevItemDelegate::DegreeDataRole).toInt(); + degree += PER_DEGREE; // 递进值 + m_deviceItemMap[machinePath]->setData(DevItemDelegate::Connecting, DevItemDelegate::ResultDataRole); + m_deviceItemMap[machinePath]->setData(degree, DevItemDelegate::DegreeDataRole); + m_deviceListView->update(m_deviceItemMap[machinePath]->index()); + } + } +} diff --git a/plugins/display/devcollaborationwidget.h b/plugins/display/devcollaborationwidget.h new file mode 100644 index 000000000..421208e00 --- /dev/null +++ b/plugins/display/devcollaborationwidget.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 . + */ +#ifndef DEVICE_COLLABORATION_WIDGET_H +#define DEVICE_COLLABORATION_WIDGET_H + +#include +#include + +DWIDGET_USE_NAMESPACE + +class CollaborationDevice; +class CollaborationDevModel; + +/*! + * \brief The DevCollaborationWidget class + * 设备跨端协同子页面 + */ +class DevCollaborationWidget : public QWidget +{ + Q_OBJECT +public: + explicit DevCollaborationWidget(QWidget *parent = nullptr); + +signals: + void sizeChanged(); + +protected: + void showEvent(QShowEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + +private slots: + void loadDevice(); + void itemClicked(const QModelIndex &index); + void itemStatusChanged(); + void refreshViewItem(); + +private: + void initUI(); + void updateDeviceListView(); + + void addItem(const CollaborationDevice *device); + void resetWidgetSize(); + +private: + CollaborationDevModel *m_deviceModel; + DListView *m_deviceListView; + QStandardItemModel *m_viewItemModel; + QMap m_deviceItemMap; + QStringList m_connectingDevices; + + QTimer *m_refreshTimer; +}; + +#endif // DEVICE_COLLABORATION_WIDGET_H diff --git a/plugins/display/devitemdelegate.cpp b/plugins/display/devitemdelegate.cpp new file mode 100644 index 000000000..73e50d222 --- /dev/null +++ b/plugins/display/devitemdelegate.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 "devitemdelegate.h" + +#include +#include +#include + +#include + +#define RADIUS_VALUE 10 +#define ITEM_SPACE 20 +#define ICON_WIDTH 16 +#define ICON_HEIGHT 16 +#define TEXT_RECT_HEIGHT 20 +#define ITEM_HEIGHT 36 +#define INDICATOR_SHADOW_OFFSET 10 + +DevItemDelegate::DevItemDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + +} + +void DevItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (!index.isValid()) + return; + + painter->setRenderHint(QPainter::Antialiasing); + QVariant var = index.data(StaticDataRole); + DevItemData itemData = var.value(); + QRect rect = option.rect; + QPen pen; + pen.setWidth(2); + + // 鼠标悬停 + if (option.state.testFlag(QStyle::State_MouseOver)) { + pen.setColor(QColor("#EBECED")); + painter->setPen(pen); + painter->setBrush(QColor("#EBECED")); + painter->drawRoundedRect(rect, RADIUS_VALUE, RADIUS_VALUE); + } + + // 选中背景(连接上和选中) + int result = index.data(ResultDataRole).toInt(); + if (option.state.testFlag(QStyle::State_Selected) && result == Connected) { + pen.setColor(QColor("#0081FF")); + painter->setPen(pen); + painter->setBrush(QColor("#0081FF")); + painter->drawRoundedRect(rect, RADIUS_VALUE, RADIUS_VALUE); + } else { + // 绘制默认背景 + pen.setColor(QColor("#EBECED")); + painter->setPen(pen); + painter->setBrush(QColor("#EBECED")); + painter->drawRoundedRect(rect, RADIUS_VALUE, RADIUS_VALUE); + } + + bool selected = (option.state.testFlag(QStyle::State_Selected) && result == Connected); + + // 绘制Icon + QString imagePath = selected ? itemData.checkedIconPath : itemData.iconPath; + QRect iconRect = QRect(rect.left() + ITEM_SPACE, rect.top() + rect.height() / 2 - ICON_HEIGHT / 2, + ICON_WIDTH, ICON_HEIGHT); + painter->drawImage(iconRect, QImage(imagePath)); + + // 绘制text + QFont font = Dtk::Widget::DFontSizeManager::instance()->t4(); + painter->setFont(font); + pen.setColor(selected ? Qt::white : Qt::black); + painter->setPen(pen); + + int textRectWidth = rect.width() - ITEM_SPACE - iconRect.width() - iconRect.width() - ITEM_SPACE; + QRect textRect = QRect(iconRect.right() + ITEM_SPACE, rect.top() + 2, + textRectWidth, rect.height()); + + QFontMetrics fm(font); + QString itemText = fm.elidedText(itemData.text, Qt::ElideRight, textRectWidth); + painter->drawText(textRect, itemText); + + switch (result) { + case ResultState::Connected: + drawResultState(painter, rect); + break; + case ResultState::Connecting: + drawWaitingState(painter, rect, index.data(DegreeDataRole).toInt()); + break; + default: + break; + } +} + +QSize DevItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(index) + return QSize(option.rect.width(), ITEM_HEIGHT); +} + +void DevItemDelegate::drawWaitingState(QPainter *painter, const QRect &rect, int degree) const +{ + int left = rect.width() - ITEM_SPACE; + int top = rect.top() + rect.height() / 2 - ICON_HEIGHT / 2; + QRect newRect(left, top, ICON_WIDTH, ICON_HEIGHT); + + painter->setRenderHint(QPainter::Antialiasing, true); + QList> indicatorColors; + for (int i = 0; i < 3; i++) + indicatorColors << createDefaultIndicatorColorList(QColor("#0081FF")); + + double radius = 16 * 0.66; + auto center = QRectF(newRect).center(); + auto indicatorRadius = radius / 2 / 2 * 1.1; + auto indicatorDegreeDelta = 360 / indicatorColors.count(); + + for (int i = 0; i < indicatorColors.count(); ++i) { + QList colors = indicatorColors.value(i); + for (int j = 0; j < colors.count(); ++j) { + double degreeCurrent = degree - j * INDICATOR_SHADOW_OFFSET + indicatorDegreeDelta * i; + auto x = (radius - indicatorRadius) * qCos(qDegreesToRadians(degreeCurrent)); + auto y = (radius - indicatorRadius) * qSin(qDegreesToRadians(degreeCurrent)); + + x = center.x() + x; + y = center.y() + y; + auto tl = QPointF(x - 1 * indicatorRadius, y - 1 * indicatorRadius); + QRectF rf(tl.x(), tl.y(), indicatorRadius * 2, indicatorRadius * 2); + + QPainterPath path; + path.addEllipse(rf); + + painter->fillPath(path, colors.value(j)); + } + } +} + +void DevItemDelegate::drawResultState(QPainter *painter, const QRect &rect) const +{ + // 绘制对勾,14x12 + int left = rect.width() - ITEM_SPACE; + int top = rect.top() + rect.height() / 2 - 6; + + QPainterPath path; + path.moveTo(left, top + 6); + path.lineTo(left + 4, top + 11); + path.lineTo(left + 12, top + 1); + + painter->drawPath(path); +} + +QList DevItemDelegate::createDefaultIndicatorColorList(QColor color) const +{ + QList colors; + QList opacitys; + opacitys << 100 << 30 << 15 << 10 << 5 << 4 << 3 << 2 << 1; + for (int i = 0; i < opacitys.count(); ++i) { + color.setAlpha(255 * opacitys.value(i) / 100); + colors << color; + } + + return colors; +} diff --git a/plugins/display/devitemdelegate.h b/plugins/display/devitemdelegate.h new file mode 100644 index 000000000..e97d3455a --- /dev/null +++ b/plugins/display/devitemdelegate.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 . + */ +#ifndef DEVITEMDELEGATE_H +#define DEVITEMDELEGATE_H + +#include + +/*! + * \brief The DevItemDelegate class + */ +class DevItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + enum DevItemDataRole { + StaticDataRole = Qt::UserRole + 1, // 静态信息 + MachinePathDataRole = Qt::UserRole + 2, // machinePath, 可唯一代表一个设备 + DegreeDataRole = Qt::UserRole + 3, // degree 绘制waiting使用的参数 + ResultDataRole = Qt::UserRole + 4 // 连接结果 + }; + + enum ResultState { + None, + Connecting, + Connected + }; + + struct DevItemData { + QString checkedIconPath; + QString iconPath; + QString text; + }; + +public: + explicit DevItemDelegate(QObject *parent = nullptr); + +protected: + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + +private: + void drawWaitingState(QPainter *painter, const QRect &rect, int degree) const; + void drawResultState(QPainter *painter, const QRect &rect) const; + QList createDefaultIndicatorColorList(QColor color) const; +}; + +Q_DECLARE_METATYPE(DevItemDelegate::DevItemData) + +#endif // DEVITEMDELEGATE_H diff --git a/plugins/display/display.json b/plugins/display/display.json new file mode 100644 index 000000000..bec81f0da --- /dev/null +++ b/plugins/display/display.json @@ -0,0 +1,3 @@ +{ + "api": "2.0.0" +} diff --git a/plugins/display/displayplugin.cpp b/plugins/display/displayplugin.cpp new file mode 100644 index 000000000..86258b1a5 --- /dev/null +++ b/plugins/display/displayplugin.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: sbw + * + * Maintainer: sbw + * + * 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 "displayplugin.h" +#include "brightnesswidget.h" +#include "displaysettingwidget.h" +#include "brightnesswidget.h" +#include "brightnessmodel.h" + +#include "../../widgets/tipswidget.h" +#include "../../frame/util/utils.h" + +#include + +#include +#include + +#include + +#define PLUGIN_STATE_KEY "enable" +#define TIME_FORMAT_KEY "Use24HourFormat" +using namespace Dock; +DisplayPlugin::DisplayPlugin(QObject *parent) + : QObject(parent) + , m_displayWidget(nullptr) + , m_displaySettingWidget(nullptr) + , m_displayTips(nullptr) + , m_model(new BrightnessModel(this)) +{ +} + +const QString DisplayPlugin::pluginName() const +{ + return "display"; +} + +const QString DisplayPlugin::pluginDisplayName() const +{ + return tr("brightness"); +} + +void DisplayPlugin::init(PluginProxyInterface *proxyInter) +{ + if (m_proxyInter == proxyInter) + return; + + m_proxyInter = proxyInter; + m_displayTips.reset(new TipsWidget); + m_displayWidget.reset(new BrightnessWidget(m_model)); + m_displayWidget->setFixedHeight(60); + m_displaySettingWidget.reset(new DisplaySettingWidget); + + m_proxyInter->itemAdded(this, pluginName()); + + connect(m_displayWidget.data(), &BrightnessWidget::brightClicked, this, [ this ] { + m_proxyInter->requestSetAppletVisible(this, QUICK_ITEM_KEY, true); + }); +} + +QWidget *DisplayPlugin::itemWidget(const QString &itemKey) +{ + if (itemKey == QUICK_ITEM_KEY) { + return m_displayWidget.data(); + } + + return nullptr; +} + +QWidget *DisplayPlugin::itemTipsWidget(const QString &itemKey) +{ + Q_UNUSED(itemKey); + + return m_displayTips.data(); +} + +QWidget *DisplayPlugin::itemPopupApplet(const QString &itemKey) +{ + if (itemKey == QUICK_ITEM_KEY) + return m_displaySettingWidget.data(); + + return nullptr; +} + +PluginFlags DisplayPlugin::flags() const +{ + return PluginFlag::Type_Common | PluginFlag::Quick_Full; +} diff --git a/plugins/display/displayplugin.h b/plugins/display/displayplugin.h new file mode 100644 index 000000000..ed1fe4064 --- /dev/null +++ b/plugins/display/displayplugin.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. + * + * Author: sbw + * + * Maintainer: sbw + * + * 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 . + */ + +#ifndef DISPLAYPLUGIN_H +#define DISPLAYPLUGIN_H + +#include "pluginsiteminterface.h" + +#include +#include +#include + +namespace Dock{ +class TipsWidget; +} + +class BrightnessWidget; +class BrightnessModel; +class DisplaySettingWidget; + +class DisplayPlugin : public QObject, PluginsItemInterface +{ + Q_OBJECT + Q_INTERFACES(PluginsItemInterface) + Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "display.json") + +public: + explicit DisplayPlugin(QObject *parent = nullptr); + + const QString pluginName() const override; + const QString pluginDisplayName() const override; + void init(PluginProxyInterface *proxyInter) override; + + QWidget *itemWidget(const QString &itemKey) override; + QWidget *itemTipsWidget(const QString &itemKey) override; + QWidget *itemPopupApplet(const QString &itemKey) override; + + PluginFlags flags() const override; + +private: + QScopedPointer m_displayWidget; + QScopedPointer m_displaySettingWidget; + QScopedPointer m_displayTips; + BrightnessModel *m_model; +}; + +#endif // DATETIMEPLUGIN_H diff --git a/plugins/display/displaysettingwidget.cpp b/plugins/display/displaysettingwidget.cpp new file mode 100644 index 000000000..f27d1e21f --- /dev/null +++ b/plugins/display/displaysettingwidget.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 "displaysettingwidget.h" +#include "brightnessadjwidget.h" +#include "devcollaborationwidget.h" + +#include +#include + +#include + +const int ItemSpacing = 10; + +DisplaySettingWidget::DisplaySettingWidget(QWidget *parent) + : QWidget(parent) + , m_brightnessAdjWidget(new BrightnessAdjWidget(this)) + , m_collaborationWidget(new DevCollaborationWidget(this)) + , m_settingBtn(new QPushButton(tr("Display setting"), this)) +{ + initUI(); + + connect(m_settingBtn, &QPushButton::clicked, this, [ this ](){ + DDBusSender().service("org.deepin.dde.ControlCenter1") + .path("/org/deepin/dde/ControlCenter1") + .interface("org.deepin.dde.ControlCenter1") + .method("ShowPage").arg(QString("display")).call(); + hide(); + }); +} + +void DisplaySettingWidget::initUI() +{ + setContentsMargins(0, 10, 0, 30); + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setMargin(0); + mainLayout->setSpacing(ItemSpacing); + + mainLayout->addWidget(m_brightnessAdjWidget); + mainLayout->addWidget(m_collaborationWidget); + mainLayout->addWidget(m_settingBtn); + mainLayout->addStretch(); + + setLayout(mainLayout); + + resizeWidgetHeight(); + connect(m_collaborationWidget, &DevCollaborationWidget::sizeChanged, + this, &DisplaySettingWidget::resizeWidgetHeight); +} + +void DisplaySettingWidget::resizeWidgetHeight() +{ + QMargins margins = this->contentsMargins(); + setFixedHeight(margins.top() + margins.bottom() + m_brightnessAdjWidget->height() + + m_collaborationWidget->height() + m_settingBtn->height() + ItemSpacing * 2); +} diff --git a/plugins/display/displaysettingwidget.h b/plugins/display/displaysettingwidget.h new file mode 100644 index 000000000..9ea0b8fc4 --- /dev/null +++ b/plugins/display/displaysettingwidget.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 ~ 2022 Uniontech Software Technology Co.,Ltd. + * + * Author: zhaoyingzhen + * + * Maintainer: zhaoyingzhen + * + * 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 . + */ +#ifndef DISPLAY_SETTING_WIDGET_H +#define DISPLAY_SETTING_WIDGET_H + +#include + +class QPushButton; +class BrightnessAdjWidget; +class DevCollaborationWidget; + +/*! + * \brief The DisplaySettingWidget class + * 显示设置页面,快捷设置面板-->亮度调节栏右边显示按钮-->此页面 + */ +class DisplaySettingWidget : public QWidget +{ + Q_OBJECT +public: + explicit DisplaySettingWidget(QWidget *parent = nullptr); + +private: + void initUI(); + void resizeWidgetHeight(); + +private: + BrightnessAdjWidget *m_brightnessAdjWidget; // 亮度调整 + DevCollaborationWidget *m_collaborationWidget; // 跨端协同 + QPushButton *m_settingBtn; // 设置按钮 +}; + + +#endif // DISPLAY_SETTING_WIDGET_H diff --git a/plugins/display/resource/ICON_Device_Headphone.svg b/plugins/display/resource/ICON_Device_Headphone.svg new file mode 100644 index 000000000..c2aeaccf2 --- /dev/null +++ b/plugins/display/resource/ICON_Device_Headphone.svg @@ -0,0 +1,17 @@ + + + -mockplus- + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/ICON_Device_Headphone_dark.svg b/plugins/display/resource/ICON_Device_Headphone_dark.svg new file mode 100644 index 000000000..7c797d1e1 --- /dev/null +++ b/plugins/display/resource/ICON_Device_Headphone_dark.svg @@ -0,0 +1,17 @@ + + + -mockplus- + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/ICON_Device_Laptop.svg b/plugins/display/resource/ICON_Device_Laptop.svg new file mode 100644 index 000000000..115314c7c --- /dev/null +++ b/plugins/display/resource/ICON_Device_Laptop.svg @@ -0,0 +1,17 @@ + + + -mockplus- + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/ICON_Device_Laptop_dark.svg b/plugins/display/resource/ICON_Device_Laptop_dark.svg new file mode 100644 index 000000000..3ba0d45f1 --- /dev/null +++ b/plugins/display/resource/ICON_Device_Laptop_dark.svg @@ -0,0 +1,17 @@ + + + -mockplus- + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/brightness.svg b/plugins/display/resource/brightness.svg new file mode 100644 index 000000000..31d4f9830 --- /dev/null +++ b/plugins/display/resource/brightness.svg @@ -0,0 +1,15 @@ + + + ICON / MenuItem / Brightness+ + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/brightnesshigh.svg b/plugins/display/resource/brightnesshigh.svg new file mode 100644 index 000000000..baeb9afcd --- /dev/null +++ b/plugins/display/resource/brightnesshigh.svg @@ -0,0 +1,3 @@ + + + diff --git a/plugins/display/resource/brightnesslow.svg b/plugins/display/resource/brightnesslow.svg new file mode 100644 index 000000000..c5a11a167 --- /dev/null +++ b/plugins/display/resource/brightnesslow.svg @@ -0,0 +1,3 @@ + + + diff --git a/plugins/display/resource/broadcast.svg b/plugins/display/resource/broadcast.svg new file mode 100644 index 000000000..f45b1ae57 --- /dev/null +++ b/plugins/display/resource/broadcast.svg @@ -0,0 +1,15 @@ + + + ICON / MenuItem / Broadcast + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/display/resource/display.qrc b/plugins/display/resource/display.qrc new file mode 100644 index 000000000..0994b934f --- /dev/null +++ b/plugins/display/resource/display.qrc @@ -0,0 +1,12 @@ + + + brightness.svg + brightnesshigh.svg + brightnesslow.svg + broadcast.svg + ICON_Device_Headphone_dark.svg + ICON_Device_Headphone.svg + ICON_Device_Laptop_dark.svg + ICON_Device_Laptop.svg + +