diff --git a/dss_example/CMakeLists.txt b/dss_example/CMakeLists.txt index 4ef1e929..1f2628cb 100644 --- a/dss_example/CMakeLists.txt +++ b/dss_example/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PUBLIC . ../src + ../dss-network-plugin Dtk6::Widget Qt6::DBus Qt6::Network @@ -35,5 +36,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Network Qt6::Widgets KF6::NetworkManagerQt + dss-network-plugin dde-network-core6 ) diff --git a/dss_example/dssscreenmanager.cpp b/dss_example/dssscreenmanager.cpp new file mode 100644 index 00000000..93d42586 --- /dev/null +++ b/dss_example/dssscreenmanager.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dssscreenmanager.h" + +#include "dsstestwidget.h" +#include "networkmodule.h" + +#include +#include + +DssScreenManager::DssScreenManager(QObject *parent) + : QObject(parent) + , m_netModule(new dde::network::NetworkPlugin(this)) +{ + m_netModule->init(); + initConnection(); + initScreen(); +} + +DssScreenManager::~DssScreenManager() +{ + qDeleteAll(m_screenWidget); + m_screenWidget.clear(); +} + +void DssScreenManager::showWindow() +{ + for (auto it = m_screenWidget.constBegin(); it != m_screenWidget.constEnd(); it++) { + showWindow(it.key(), it.value()); + } +} + +void DssScreenManager::initConnection() +{ + connect(qApp, &QGuiApplication::screenAdded, this, &DssScreenManager::onScreenAdded); + connect(qApp, &QGuiApplication::screenRemoved, this, &DssScreenManager::onScreenRemoved); +} + +void DssScreenManager::initScreen() +{ + QList screens = QGuiApplication::screens(); + for (QScreen *screen : screens) { + DssTestWidget *testWidget = new DssTestWidget(m_netModule); + m_screenWidget[screen] = testWidget; + } +} + +void DssScreenManager::showWindow(QScreen *screen, DssTestWidget *testWidget) +{ + const QRect screenGeometry = screen->geometry(); + testWidget->resize(330, 800); + testWidget->move(screenGeometry.x() + (screenGeometry.width() - testWidget->width()) / 2, (screenGeometry.height() - testWidget->height()) / 2); + testWidget->show(); +} + +void DssScreenManager::onScreenAdded(QScreen *screen) +{ + DssTestWidget *testWidget = new DssTestWidget(m_netModule); + m_screenWidget[screen] = testWidget; + showWindow(screen, testWidget); +} + +void DssScreenManager::onScreenRemoved(QScreen *screen) +{ + if (m_screenWidget.contains(screen)) { + DssTestWidget *testWidget = m_screenWidget[screen]; + m_screenWidget.remove(screen); + testWidget->deleteLater(); + } +} diff --git a/dss_example/dssscreenmanager.h b/dss_example/dssscreenmanager.h new file mode 100644 index 00000000..374a405a --- /dev/null +++ b/dss_example/dssscreenmanager.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DSSSCREENMANAGER_H +#define DSSSCREENMANAGER_H + +#include +#include + +class DssTestWidget; +class QScreen; + +namespace dde { +namespace network { +class NetworkPlugin; +} // namespace network +} // namespace dde + +class DssScreenManager : public QObject +{ + Q_OBJECT + +public: + explicit DssScreenManager(QObject *parent = nullptr); + ~DssScreenManager(); + void showWindow(); + +private: + void initConnection(); + void initScreen(); + void showWindow(QScreen *screen, DssTestWidget *testWidget); + +protected: + void onScreenAdded(QScreen *screen); + void onScreenRemoved(QScreen *screen); + +private: + QMap m_screenWidget; + dde::network::NetworkPlugin *m_netModule; +}; + +#endif // DSSSCREENMANAGER_H diff --git a/dss_example/dsstestwidget.cpp b/dss_example/dsstestwidget.cpp index 2e1214cc..b78e0b40 100644 --- a/dss_example/dsstestwidget.cpp +++ b/dss_example/dsstestwidget.cpp @@ -1,39 +1,62 @@ // SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // -// SPDX-License-Identifier: LGPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later #include "dsstestwidget.h" -#include -#include -#include + +#include "networkmodule.h" +#include "popupwindow.h" + +#include #include -#include -#include #include -#include +#include +using namespace dde::network; using namespace Dtk::Widget; DGUI_USE_NAMESPACE -DssTestWidget::DssTestWidget(QWidget *parent) +DssTestWidget::DssTestWidget(dde::network::NetworkPlugin *networkPlugin, QWidget *parent) : QWidget(parent) - , m_button(nullptr) + , m_pModule(networkPlugin) + , m_container(nullptr) + , m_tipContainer(nullptr) { - m_button = new Dtk::Widget::DFloatingButton(this); - m_button->setIconSize(QSize(26, 26)); - m_button->setFixedSize(QSize(52, 52)); - m_button->setAutoExclusive(true); - m_button->setBackgroundRole(DPalette::Button); - m_button->setIcon(QIcon("network-online-symbolic")); - m_button->installEventFilter(this); - - // 创建一个简单的布局 - QHBoxLayout *layout = new QHBoxLayout(this); - layout->setSpacing(0); + QWidget *iconWidget = new QWidget(this); + m_iconButton = new DFloatingButton(iconWidget); + m_iconButton->setIconSize(QSize(26, 26)); + m_iconButton->setFixedSize(QSize(52, 52)); + m_iconButton->setAutoExclusive(true); + QPalette palette = m_iconButton->palette(); + palette.setColor(QPalette::ColorRole::Window, Qt::transparent); + m_iconButton->setPalette(palette); + m_iconButton->installEventFilter(this); + connect(m_iconButton, &Dtk::Widget::DFloatingButton::clicked, this, &DssTestWidget::onClickButton); + + QHBoxLayout *iconLayout = new QHBoxLayout(iconWidget); + iconLayout->setAlignment(Qt::AlignHCenter); + iconLayout->addWidget(m_iconButton); + + QPalette paletteSelf = this->palette(); + paletteSelf.setColor(QPalette::ColorRole::Window, Qt::darkBlue); + setAutoFillBackground(true); + setPalette(paletteSelf); + + QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(m_button); + layout->addStretch(); + layout->addWidget(iconWidget); + + QHBoxLayout *iconButtonLayout = new QHBoxLayout(m_iconButton); + QWidget *itemWidget = m_pModule->itemWidget(); + itemWidget->setParent(m_iconButton); + iconButtonLayout->addWidget(itemWidget); + + installEventFilter(this); + itemWidget->installEventFilter(this); + m_iconButton->installEventFilter(this); } DssTestWidget::~DssTestWidget() @@ -42,24 +65,85 @@ DssTestWidget::~DssTestWidget() bool DssTestWidget::eventFilter(QObject *watched, QEvent *event) { - if (watched == m_button) { + if (watched == m_iconButton) { + // 当鼠标移入的时候显示提示信息 switch (event->type()) { - case QEvent::MouseButtonPress: { - QMouseEvent *mouseEvent = static_cast(event); - if (mouseEvent->button() == Qt::RightButton) { - QMessageBox::information(this, "DSS Example", "右键点击 - 网络测试程序"); - } else if (mouseEvent->button() == Qt::LeftButton) { - QMessageBox::information(this, "DSS Example", "左键点击 - 网络测试程序"); - } + case QEvent::Enter: { + if (!m_tipContainer) { + QWidget *tipWidget = m_pModule->itemTipsWidget(); + m_tipContainer = new PopupWindow(this); + m_tipContainer->setContent(tipWidget); + m_tipContainer->resizeWithContent(); + m_tipContainer->setArrowX(tipWidget->width() / 2); } + m_tipContainer->raise(); + m_tipContainer->show(QPoint(rect().center().x(), m_iconButton->parentWidget()->y())); + } break; + case QEvent::Leave: { + m_tipContainer->hide(); break; - case QEvent::Enter: - break; - case QEvent::Leave: + } + default: break; - default: break; } } - return QWidget::eventFilter(watched, event); } + +void DssTestWidget::resizeEvent(QResizeEvent *event) +{ + if (m_container && m_container->isVisible()) { + m_container->resizeWithContent(); + m_container->show(QPoint(rect().width() / 2, m_iconButton->parentWidget()->y())); + } + QWidget::resizeEvent(event); +} + +void DssTestWidget::mousePressEvent(QMouseEvent *event) +{ + if (m_tipContainer && m_tipContainer->isVisible()) + m_tipContainer->hide(); + if (m_container && m_container->isVisible()) + m_container->hide(); + + QWidget::mousePressEvent(event); +} + +void DssTestWidget::onClickButton() +{ + if (!m_pModule->content()) + return; + + // 左键弹出菜单 + if (!m_container) { + m_container = new PopupWindow(this); + connect(m_container, &PopupWindow::contentDetach, this, [ this ] { + m_container->setContent(nullptr); + m_container->hide(); + }); + } + static QWidget *netlistWidget = nullptr; + if (!netlistWidget) { + netlistWidget = m_pModule->content(); + } + netlistWidget->setParent(m_container); + netlistWidget->adjustSize(); + m_container->setContent(netlistWidget); + m_container->resizeWithContent(); + m_container->setArrowX(m_container->width() / 2); + + if (m_container->isVisible()) { + m_container->hide(); + if (m_tipContainer) { + m_tipContainer->toggle(); + } + } else { + if (m_tipContainer) { + m_tipContainer->hide(); + } + QWidget *content = m_container->getContent(); + content->adjustSize(); + m_container->resizeWithContent(); + m_container->show(QPoint(rect().width() / 2, m_iconButton->parentWidget()->y())); + } +} diff --git a/dss_example/dsstestwidget.h b/dss_example/dsstestwidget.h index 1f39c0a5..18e91606 100644 --- a/dss_example/dsstestwidget.h +++ b/dss_example/dsstestwidget.h @@ -1,33 +1,46 @@ // SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // -// SPDX-License-Identifier: LGPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later #ifndef DSSTESTWIDGET_H #define DSSTESTWIDGET_H +#include + #include -namespace Dtk { - namespace Widget { - class DFloatingButton; - } -} +class PopupWindow; + +namespace dde { +namespace network { +class NetworkPlugin; +} // namespace network +} // namespace dde class QPushButton; +using namespace Dtk::Widget; class DssTestWidget : public QWidget { Q_OBJECT public: - DssTestWidget(QWidget *parent = Q_NULLPTR); - ~DssTestWidget(); + explicit DssTestWidget(dde::network::NetworkPlugin *networkPlugin, QWidget *parent = Q_NULLPTR); + ~DssTestWidget() override; -private: - bool eventFilter(QObject *watched, QEvent *event); +protected: + bool eventFilter(QObject *watched, QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + +protected slots: + void onClickButton(); private: - Dtk::Widget::DFloatingButton *m_button; + dde::network::NetworkPlugin *m_pModule; + DFloatingButton *m_iconButton; + PopupWindow *m_container; + PopupWindow *m_tipContainer; }; #endif // DSSTESTWIDGET_H diff --git a/dss_example/main.cpp b/dss_example/main.cpp index 6f10623e..d3c2ecd4 100644 --- a/dss_example/main.cpp +++ b/dss_example/main.cpp @@ -1,23 +1,49 @@ // SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // -// SPDX-License-Identifier: LGPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later +#include "dssscreenmanager.h" #include "dsstestwidget.h" +#include "networkcontroller.h" + +#include #include -#include using namespace std; +using namespace dde::network; int main(int argc, char *argv[]) { QApplication app(argc, argv); - DssTestWidget testPluginWidget; - QScreen *deskdop = QApplication::primaryScreen(); - testPluginWidget.move((deskdop->size().width() - testPluginWidget.width()) / 2, (deskdop->size().height() - testPluginWidget.height()) / 2); + QString applicationName("example-lock"); + if (argc > 1) { + applicationName = QString("%1-%2").arg("example").arg(argv[1]); + } + + app.setApplicationName(applicationName); + + DGuiApplicationHelper::instance()->setPaletteType(DGuiApplicationHelper::LightType); + DPalette pa = DGuiApplicationHelper::instance()->applicationPalette(); + pa.setColor(QPalette::Normal, DPalette::WindowText, QColor("#FFFFFF")); + pa.setColor(QPalette::Normal, DPalette::Text, QColor("#FFFFFF")); + pa.setColor(QPalette::Normal, DPalette::AlternateBase, QColor(0, 0, 0, 76)); + pa.setColor(QPalette::Normal, DPalette::Button, QColor(255, 255, 255, 76)); + pa.setColor(QPalette::Normal, DPalette::Light, QColor(255, 255, 255, 76)); + pa.setColor(QPalette::Normal, DPalette::Dark, QColor(255, 255, 255, 76)); + pa.setColor(QPalette::Normal, DPalette::ButtonText, QColor("#FFFFFF")); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::WindowText, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::Text, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::AlternateBase, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::Button, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::Light, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::Dark, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::generatePaletteColor(pa, DPalette::ButtonText, DGuiApplicationHelper::LightType); + DGuiApplicationHelper::instance()->setApplicationPalette(pa); - testPluginWidget.show(); + DssScreenManager dssManager; + dssManager.showWindow(); return app.exec(); } diff --git a/dss_example/popupwindow.cpp b/dss_example/popupwindow.cpp new file mode 100644 index 00000000..d8cd2e04 --- /dev/null +++ b/dss_example/popupwindow.cpp @@ -0,0 +1,130 @@ +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "popupwindow.h" + +#include +#include + +PopupWindow::PopupWindow(QWidget *parent) + : DArrowRectangle(ArrowBottom, FloatWidget, parent) +{ + setMargin(0); + + setBackgroundColor(QColor(235, 235, 235, 80)); + setBorderColor(QColor(235, 235, 235, 80)); + + setWindowFlags(Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); + setShadowBlurRadius(20); + setRadius(6); + setShadowYOffset(2); + setShadowXOffset(0); + setArrowWidth(18); + setArrowHeight(10); +} + +PopupWindow::~PopupWindow() +{ +} + +void PopupWindow::setContent(QWidget *content) +{ + QWidget *lastWidget = getContent(); + if (lastWidget) + lastWidget->removeEventFilter(this); + + if (content) { + content->installEventFilter(this); + } + + QAccessibleEvent event(this, QAccessible::NameChanged); + QAccessible::updateAccessibility(&event); + + if (content && !content->objectName().trimmed().isEmpty()) + setAccessibleName(content->objectName() + "-popup"); + + DArrowRectangle::setContent(content); +} + +void PopupWindow::toggle(const QPoint &pos) +{ + isVisible() ? hide() : show(pos); +} + +void PopupWindow::show(const QPoint &pos) +{ + m_lastPoint = pos; + if (getContent()) + getContent()->setVisible(true); + DArrowRectangle::show(pos.x(), pos.y()); +} + +void PopupWindow::toggle() +{ + isVisible() ? hide() : show(m_lastPoint); +} + +void PopupWindow::hide() +{ + if (getContent()) + getContent()->setVisible(false); + Q_EMIT visibleChanged(false); + DArrowRectangle::hide(); +} + +void PopupWindow::showEvent(QShowEvent *e) +{ + Q_EMIT visibleChanged(true); + DArrowRectangle::showEvent(e); + + QMetaObject::invokeMethod(this, &PopupWindow::ensureRaised); +} + +void PopupWindow::enterEvent(QEnterEvent *e) +{ + DArrowRectangle::enterEvent(e); + + QMetaObject::invokeMethod(this, &PopupWindow::ensureRaised); +} + +bool PopupWindow::eventFilter(QObject *o, QEvent *e) +{ + if (o != getContent()) + return false; + + switch (e->type()) { + case QEvent::Resize: { + // FIXME: ensure position move after global mouse release event + // 目的是为了在content resize之后重新设置弹窗的位置和大小 + if (isVisible()) { + QMetaObject::invokeMethod(this, [ this ] { + if (isVisible()) + show(m_lastPoint); + }, Qt::QueuedConnection); + } + } + break; + case QEvent::ParentChange: { + emit contentDetach(); + } + break; + default: + break; + } + + return false; +} + +void PopupWindow::ensureRaised() +{ + if (!isVisible()) + return; + + QWidget *content = getContent(); + if (!content || !content->isVisible()) { + setVisible(false); + } else { + raise(); + } +} diff --git a/dss_example/popupwindow.h b/dss_example/popupwindow.h new file mode 100644 index 00000000..52f46d98 --- /dev/null +++ b/dss_example/popupwindow.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef POPUPWINDOW_H +#define POPUPWINDOW_H + +#include + +class PopupWindow : public Dtk::Widget::DArrowRectangle +{ + Q_OBJECT + +public: + explicit PopupWindow(QWidget *parent = 0); + ~PopupWindow(); + + bool model() const; + + void setContent(QWidget *content); + + using Dtk::Widget::DArrowRectangle::show; + void show(const QPoint &pos); + void toggle(); + void toggle(const QPoint &pos); + void hide(); + +protected: + void showEvent(QShowEvent *e) override; + void enterEvent(QEnterEvent *e) override; + bool eventFilter(QObject *o, QEvent *e) override; + +signals: + void visibleChanged(bool visible); + void contentDetach(); + +private slots: + void ensureRaised(); + +private: + QPoint m_lastPoint; +}; + +#endif // POPUPWINDOW_H