From 56b3540d33138c9bf636e7bba380761977c8fd3a Mon Sep 17 00:00:00 2001 From: ZhangTingAn Date: Wed, 24 Apr 2024 14:53:27 +0800 Subject: [PATCH] feat: [core] add header to dock Widget support expand/fold operation --- src/common/util/eventdefinitions.h | 5 ++ src/plugins/core/gui/dockheader.cpp | 41 ++++++++++++ src/plugins/core/gui/dockheader.h | 25 ++++++++ src/plugins/core/gui/workspacewidget.cpp | 11 +++- src/plugins/core/gui/workspacewidget.h | 6 +- src/plugins/core/uicontroller/controller.cpp | 64 ++++++++++++++++--- src/plugins/core/uicontroller/mainwindow.cpp | 61 +++++++++++++++++- src/plugins/core/uicontroller/mainwindow.h | 5 ++ src/plugins/project/mainframe/projecttree.cpp | 2 + .../transceiver/projectcorereceiver.cpp | 6 +- src/services/window/windowservice.h | 4 ++ 11 files changed, 216 insertions(+), 14 deletions(-) create mode 100644 src/plugins/core/gui/dockheader.cpp create mode 100644 src/plugins/core/gui/dockheader.h diff --git a/src/common/util/eventdefinitions.h b/src/common/util/eventdefinitions.h index 0887b45b3..288af15aa 100644 --- a/src/common/util/eventdefinitions.h +++ b/src/common/util/eventdefinitions.h @@ -106,6 +106,11 @@ OPI_OBJECT(options, OPI_INTERFACE(configSaved) ) +OPI_OBJECT(workspace, + OPI_INTERFACE(expandAll) + OPI_INTERFACE(foldAll) + ) + struct AnalysedData { struct TokenMap diff --git a/src/plugins/core/gui/dockheader.cpp b/src/plugins/core/gui/dockheader.cpp new file mode 100644 index 000000000..1b000f7e0 --- /dev/null +++ b/src/plugins/core/gui/dockheader.cpp @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockheader.h" + +#include + +#include +#include + +DWIDGET_USE_NAMESPACE + +class DockHeaderPrivate{ + friend class DockHeader; + + QHBoxLayout *mainLayout { nullptr }; +}; + +DockHeader::DockHeader(QWidget *parent) + : DWidget(parent), d(new DockHeaderPrivate) +{ + setAutoFillBackground(true); + setBackgroundRole(DPalette::Base); + + d->mainLayout = new QHBoxLayout(this); + d->mainLayout->setContentsMargins(0, 0, 0, 0); + d->mainLayout->setAlignment(Qt::AlignRight); +} + +DockHeader::~DockHeader() +{ + if (d) + delete d; +} + +void DockHeader::addToolButton(DToolButton *btn) +{ + btn->setFixedSize(20, 20); + d->mainLayout->insertWidget(0, btn); +} diff --git a/src/plugins/core/gui/dockheader.h b/src/plugins/core/gui/dockheader.h new file mode 100644 index 000000000..20570cb1d --- /dev/null +++ b/src/plugins/core/gui/dockheader.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DOCKHEADER_H +#define DOCKHEADER_H + +#include +#include + +class DockHeaderPrivate; +class DockHeader : public DTK_WIDGET_NAMESPACE::DWidget +{ + Q_OBJECT +public: + explicit DockHeader(QWidget *parent = nullptr); + ~DockHeader(); + + void addToolButton(DTK_WIDGET_NAMESPACE::DToolButton *btn); + +private: + DockHeaderPrivate *d; +}; + +#endif // DOCKHEADER_H diff --git a/src/plugins/core/gui/workspacewidget.cpp b/src/plugins/core/gui/workspacewidget.cpp index 363ddfabf..2a7a57c60 100644 --- a/src/plugins/core/gui/workspacewidget.cpp +++ b/src/plugins/core/gui/workspacewidget.cpp @@ -26,6 +26,7 @@ void WorkspaceWidget::initUi() setMinimumWidth(kMinimumWidth); editWorkspaceWidget = new DFrame(this); + editWorkspaceWidget->setLineWidth(0); DStyle::setFrameRadius(editWorkspaceWidget, 0); stackEditWorkspaceWidget = new DStackedWidget(this); workspaceTabBar = new DFrame(this); @@ -74,12 +75,20 @@ void WorkspaceWidget::addWorkspaceWidget(const QString &title, AbstractWidget *t bool WorkspaceWidget::switchWidgetWorkspace(const QString &title) { - stackEditWorkspaceWidget->setCurrentWidget(editWorkspaceWidgets[title]); + auto widget = editWorkspaceWidgets[title]; + stackEditWorkspaceWidget->setCurrentWidget(widget); for (auto it = workspaceTabButtons.begin(); it != workspaceTabButtons.end(); ++it) { it.value()->setChecked(false); if (it.key() == title) it.value()->setChecked(true); } + emit expandStateChange(widget->property("canExpand").toBool()); + return false; } + +bool WorkspaceWidget::getCurrentExpandState() +{ + return stackEditWorkspaceWidget->currentWidget()->property("canExpand").toBool(); +} diff --git a/src/plugins/core/gui/workspacewidget.h b/src/plugins/core/gui/workspacewidget.h index 43bc1047f..ed3301463 100644 --- a/src/plugins/core/gui/workspacewidget.h +++ b/src/plugins/core/gui/workspacewidget.h @@ -23,6 +23,10 @@ class WorkspaceWidget : public DWidget void addWorkspaceWidget(const QString &title, AbstractWidget *treeWidget, const QString &iconName); bool switchWidgetWorkspace(const QString &title); + bool getCurrentExpandState(); + +signals: + void expandStateChange(bool canExpand); private: void initUi(); @@ -30,7 +34,7 @@ class WorkspaceWidget : public DWidget QVBoxLayout *mainLayout { nullptr }; QMap workspaceWidgets; - DWidget *editWorkspaceWidget { nullptr }; + DFrame *editWorkspaceWidget { nullptr }; QMap editWorkspaceWidgets; QMap workspaceTabButtons; diff --git a/src/plugins/core/uicontroller/controller.cpp b/src/plugins/core/uicontroller/controller.cpp index 96848d62c..d5d9d73c8 100644 --- a/src/plugins/core/uicontroller/controller.cpp +++ b/src/plugins/core/uicontroller/controller.cpp @@ -83,6 +83,7 @@ class ControllerPrivate DWidget *contextWidget { nullptr }; DStackedWidget *stackContextWidget { nullptr }; DFrame *contextTabBar { nullptr }; + QHBoxLayout *contextButtonLayout { nullptr }; bool contextWidgetAdded { false }; WindowStatusBar *statusBar { nullptr }; @@ -166,6 +167,12 @@ void Controller::registerService() if (!windowService->showWidgetAtPosition) { windowService->showWidgetAtPosition = std::bind(&Controller::showWidgetAtPosition, this, _1, _2, _3); } + if (!windowService->deleteDockHeader) { + windowService->deleteDockHeader = std::bind(&MainWindow::deleteDockHeader, d->mainWindow, _1); + } + if (!windowService->addToolBtnToDockHeader) { + windowService->addToolBtnToDockHeader = std::bind(&MainWindow::addToolBtnToDockHeader, d->mainWindow, _1, _2); + } if (!windowService->setDockWidgetFeatures) { windowService->setDockWidgetFeatures = std::bind(&MainWindow::setDockWidgetFeatures, d->mainWindow, _1, _2); } @@ -426,11 +433,7 @@ void Controller::addContextWidget(const QString &title, AbstractWidget *contextW if (!isVisible) tabBtn->hide(); - QHBoxLayout *btnLayout = static_cast(d->contextTabBar->layout()); - - btnLayout->addWidget(tabBtn); - btnLayout->setSpacing(0); - btnLayout->setContentsMargins(12, 6, 12, 6); + d->contextButtonLayout->addWidget(tabBtn); connect(tabBtn, &DPushButton::clicked, qWidget, [=] { switchContextWidget(title); }); @@ -442,6 +445,7 @@ void Controller::showContextWidget() { if (!d->contextWidgetAdded) { d->mainWindow->addWidget(WN_CONTEXTWIDGET, d->contextWidget, Position::Bottom); + d->mainWindow->deleteDockHeader(WN_CONTEXTWIDGET); d->contextWidgetAdded = true; } else { d->mainWindow->showWidget(WN_CONTEXTWIDGET); @@ -826,10 +830,33 @@ void Controller::initContextWidget() d->contextTabBar->setLineWidth(0); d->contextTabBar->setFixedHeight(40); - QHBoxLayout *contextTabLayout = new QHBoxLayout(d->contextTabBar); - contextTabLayout->setAlignment(Qt::AlignLeft); + d->contextButtonLayout = new QHBoxLayout; + d->contextButtonLayout->setSpacing(0); + d->contextButtonLayout->setContentsMargins(12, 6, 12, 6); + d->contextButtonLayout->setAlignment(Qt::AlignLeft); + + DToolButton *hideBtn = new DToolButton(d->contextTabBar); + hideBtn->setFixedSize(35, 35); + hideBtn->setIcon(QIcon::fromTheme("expand")); + connect(hideBtn, &DToolButton::clicked, d->contextWidget, [=](){ + if (d->stackContextWidget->isVisible()) { + d->stackContextWidget->hide(); + hideBtn->setIcon(QIcon::fromTheme("fold")); + d->contextWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + d->mainWindow->resizeDock(WN_CONTEXTWIDGET, d->contextTabBar->size()); + } else { + d->contextWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + d->stackContextWidget->show(); + hideBtn->setIcon(QIcon::fromTheme("expand")); + } + }); + + QHBoxLayout *tabbarLayout = new QHBoxLayout(d->contextTabBar); + tabbarLayout->setContentsMargins(0, 0, 0, 0); + tabbarLayout->addLayout(d->contextButtonLayout); + tabbarLayout->addWidget(hideBtn, Qt::AlignRight); - QVBoxLayout *contextVLayout = new QVBoxLayout(); + QVBoxLayout *contextVLayout = new QVBoxLayout; contextVLayout->setContentsMargins(0, 0, 0, 0); contextVLayout->setSpacing(0); contextVLayout->addWidget(d->contextTabBar); @@ -929,7 +956,28 @@ void Controller::showWorkspace() if (d->showWorkspace != true) { d->mainWindow->addWidget(WN_WORKSPACE, d->workspace, Position::Left); d->mainWindow->resizeDock(WN_WORKSPACE, QSize(300, 300)); + d->showWorkspace = true; + + DToolButton *expandAll = new DToolButton(d->workspace); + expandAll->setToolTip(tr("Expand All")); + expandAll->setIcon(QIcon::fromTheme("ide")); + d->mainWindow->addToolBtnToDockHeader(WN_WORKSPACE, expandAll); + connect(expandAll, &DToolButton::clicked, this, [](){workspace.expandAll();}); + + DToolButton *foldAll = new DToolButton(d->workspace); + foldAll->setToolTip(tr("Fold All")); + foldAll->setIcon(QIcon::fromTheme("ide")); + d->mainWindow->addToolBtnToDockHeader(WN_WORKSPACE, foldAll); + connect(foldAll, &DToolButton::clicked, this, [](){workspace.foldAll();}); + + expandAll->setVisible(d->workspace->getCurrentExpandState()); + foldAll->setVisible(d->workspace->getCurrentExpandState()); + + connect(d->workspace, &WorkspaceWidget::expandStateChange, this, [=](bool canExpand){ + expandAll->setVisible(canExpand); + foldAll->setVisible(canExpand); + }); } d->mainWindow->showWidget(WN_WORKSPACE); diff --git a/src/plugins/core/uicontroller/mainwindow.cpp b/src/plugins/core/uicontroller/mainwindow.cpp index 8420cf7fc..5636364f0 100644 --- a/src/plugins/core/uicontroller/mainwindow.cpp +++ b/src/plugins/core/uicontroller/mainwindow.cpp @@ -77,18 +77,45 @@ MainWindow::~MainWindow() DDockWidget *MainWindow::createDockWidget(DWidget *widget) { DDockWidget *dock = new DDockWidget(this); - dock->setFeatures(QDockWidget::NoDockWidgetFeatures); + dock->setFeatures(QDockWidget::AllDockWidgetFeatures); - //todo(zta: set titleBar if (dock->titleBarWidget()) delete dock->titleBarWidget(); - dock->setTitleBarWidget(new DWidget(this)); + + auto header = new DockHeader(this); + dock->setTitleBarWidget(header); dock->setWidget(widget); return dock; } +void MainWindow::deleteDockHeader(const QString &name) +{ + if (!d->dockList.contains(name)) + return; + + auto dock = d->dockList[name]; + auto titleBar = dock->titleBarWidget(); + + if (titleBar) + delete titleBar; + + dock->setTitleBarWidget(new QWidget()); +} + +void MainWindow::addToolBtnToDockHeader(const QString &dockName, DToolButton *btn) +{ + if (!d->dockList.contains(dockName)) + return; + + auto dock = d->dockList[dockName]; + auto titleBar = qobject_cast(dock->titleBarWidget()); + + if (titleBar) + titleBar->addToolButton(btn); +} + void MainWindow::addWidget(const QString &name, QWidget *widget, Position pos) { if (d->dockList.contains(name)) { @@ -111,11 +138,15 @@ void MainWindow::addWidget(const QString &name, QWidget *widget, Position pos) auto area = positionTodockArea(pos); auto dock = createDockWidget(widget); + addDockWidget(area, dock); //initial dock size , modify it as other dock which on same position resizeDock(dock); d->dockList.insert(name, dock); + + //add close btn to dock`s header + initDockHeader(dock, pos); } void MainWindow::addWidget(const QString &name, QWidget *widget, dpfservice::Position pos, Qt::Orientation orientation) @@ -138,6 +169,30 @@ void MainWindow::addWidget(const QString &name, QWidget *widget, dpfservice::Pos //initial dock size , modify it as other dock which on same position resizeDock(dock); d->dockList.insert(name, dock); + + //add close btn to dock`s header + initDockHeader(dock, pos); +} + +void MainWindow::initDockHeader(DDockWidget *dock, dpfservice::Position pos) +{ + if (pos != Position::Left) + return; + + auto closeBtn = new DToolButton(dock); + closeBtn->setCheckable(true); + closeBtn->setIcon(QIcon::fromTheme("go-previous").pixmap(20)); + + addToolBtnToDockHeader(d->dockList.key(dock), closeBtn); + + connect(closeBtn, &DToolButton::clicked, dock, [=](){ + if (dock->isVisible()) { + dock->hide(); + } else { + dock->show(); + resizeDock(d->dockList.key(dock), QSize(300, 300)); + } + }); } void MainWindow::resizeDock(QDockWidget *dock) diff --git a/src/plugins/core/uicontroller/mainwindow.h b/src/plugins/core/uicontroller/mainwindow.h index f48a3f6e5..57c7ae1fc 100644 --- a/src/plugins/core/uicontroller/mainwindow.h +++ b/src/plugins/core/uicontroller/mainwindow.h @@ -5,6 +5,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include "services/window/windowcontroller.h" +#include "gui/dockheader.h" + #include #include #include @@ -40,6 +42,8 @@ class MainWindow : public DMainWindow void removeWidget(const QString &name); void removeWidget(Position pos); + void deleteDockHeader(const QString &name); + void addToolBtnToDockHeader(const QString &dockName, DToolButton *btn); void setDockWidgetFeatures(const QString &name, QDockWidget::DockWidgetFeatures feature); //size(width,heigt) width used for widget in Left and Right. //heigth used for widget in top and bottom @@ -63,6 +67,7 @@ class MainWindow : public DMainWindow MainWindowPrivate *d; DDockWidget *createDockWidget(DWidget *widget); + void initDockHeader(DDockWidget *dock, Position pos); void addTopToolBar(); void removeAllDockWidget(); diff --git a/src/plugins/project/mainframe/projecttree.cpp b/src/plugins/project/mainframe/projecttree.cpp index 6b4183909..f3fbe5496 100644 --- a/src/plugins/project/mainframe/projecttree.cpp +++ b/src/plugins/project/mainframe/projecttree.cpp @@ -80,6 +80,8 @@ ProjectTree::ProjectTree(QWidget *parent) d->delegate = new ProjectDelegate(this); setItemDelegate(d->delegate); this->setDragEnabled(true); + + setProperty("canExpand", true); } ProjectTree::~ProjectTree() diff --git a/src/plugins/project/transceiver/projectcorereceiver.cpp b/src/plugins/project/transceiver/projectcorereceiver.cpp index e93dc6d36..ed255204c 100644 --- a/src/plugins/project/transceiver/projectcorereceiver.cpp +++ b/src/plugins/project/transceiver/projectcorereceiver.cpp @@ -23,7 +23,7 @@ dpf::EventHandler::Type ProjectCoreReceiver::type() QStringList ProjectCoreReceiver::topics() { - return {project.topic}; //绑定menu 事件 + return {project.topic, workspace.topic}; //绑定menu 事件 } void ProjectCoreReceiver::eventProcess(const dpf::Event &event) @@ -56,6 +56,10 @@ void ProjectCoreReceiver::eventProcess(const dpf::Event &event) } } } + } else if (event.data() == workspace.expandAll.name) { + ProjectKeeper::instance()->treeView()->expandAll(); + } else if (event.data() == workspace.foldAll.name) { + ProjectKeeper::instance()->treeView()->collapseAll(); } } diff --git a/src/services/window/windowservice.h b/src/services/window/windowservice.h index 16bdd617c..70c79bfb7 100644 --- a/src/services/window/windowservice.h +++ b/src/services/window/windowservice.h @@ -11,6 +11,8 @@ #include +#include + #include #include @@ -92,6 +94,8 @@ class WindowService final : public dpf::PluginService, dpf::AutoServiceRegister< DPF_INTERFACE(void, setDockWidgetFeatures, const QString &name, QDockWidget::DockWidgetFeatures feature); + DPF_INTERFACE(void, deleteDockHeader, const QString &name); + DPF_INTERFACE(void, addToolBtnToDockHeader, const QString &name, DTK_WIDGET_NAMESPACE::DToolButton *btn); /*! * \brief add navigationItem to leftToolBar * \param action