From c7219484bcdfbf87d6557c2b0b3b5b694af99fe6 Mon Sep 17 00:00:00 2001 From: Grzegorz Wojciechowski Date: Wed, 21 Aug 2024 16:00:53 +0200 Subject: [PATCH] Make DockTitleBar customizable --- src/framework/dockwindow/docktypes.h | 1 + .../dockwindow/internal/dockframemodel.cpp | 22 ++++ .../dockwindow/internal/dockframemodel.h | 7 ++ .../dockwindow/qml/Muse/Dock/DockFrame.qml | 8 +- .../dockwindow/qml/Muse/Dock/DockTitleBar.qml | 116 +++++++++++------- .../dockwindow/view/dockpanelview.cpp | 17 +++ src/framework/dockwindow/view/dockpanelview.h | 5 + 7 files changed, 132 insertions(+), 44 deletions(-) diff --git a/src/framework/dockwindow/docktypes.h b/src/framework/dockwindow/docktypes.h index 8bf0747476b77..6161bbe62b809 100644 --- a/src/framework/dockwindow/docktypes.h +++ b/src/framework/dockwindow/docktypes.h @@ -30,6 +30,7 @@ namespace muse::dock { inline const char* CONTEXT_MENU_MODEL_PROPERTY("contextMenuModel"); inline const char* DOCK_PANEL_PROPERTY("dockPanel"); +inline const char* TITLEBAR_PROPERTY("titleBar"); //! NOTE: need to be synchronized with Window shadow(see DockFloatingWindow margins) inline constexpr int DOCK_WINDOW_SHADOW(8); diff --git a/src/framework/dockwindow/internal/dockframemodel.cpp b/src/framework/dockwindow/internal/dockframemodel.cpp index 76eae7b2303fd..f83d7283102ba 100644 --- a/src/framework/dockwindow/internal/dockframemodel.cpp +++ b/src/framework/dockwindow/internal/dockframemodel.cpp @@ -25,6 +25,7 @@ #include #include +#include "private/TitleBar_p.h" #include "thirdparty/KDDockWidgets/src/private/Frame_p.h" #include "uicomponents/view/abstractmenumodel.h" @@ -93,6 +94,11 @@ QVariantList DockFrameModel::tabs() const return result; } +QQmlComponent* DockFrameModel::titleBar() const +{ + return m_titleBar; +} + bool DockFrameModel::titleBarVisible() const { return m_titleBarVisible; @@ -139,6 +145,7 @@ void DockFrameModel::listenChangesInFrame() && (properties.location == Location::Top || properties.location == Location::Bottom); setIsHorizontalPanel(isHorizontalPanel); + updateTitleBar(); bool visible = (allDocks.size() == 1) && (properties.type == DockType::Panel) && (properties.floatable || properties.closable); setTitleBarVisible(visible); @@ -187,6 +194,21 @@ void DockFrameModel::updateNavigationSection() } } +QQmlComponent* DockFrameModel::currentTitleBar() const +{ + QQmlComponent* titleBar = currentDockProperty(TITLEBAR_PROPERTY).value(); + return titleBar; +} + +void DockFrameModel::updateTitleBar() +{ + QQmlComponent* tb = currentTitleBar(); + if (m_titleBar != tb) { + m_titleBar = tb; + emit titleBarChanged(); + } +} + QObject* DockFrameModel::navigationSection() const { return m_navigationSection; diff --git a/src/framework/dockwindow/internal/dockframemodel.h b/src/framework/dockwindow/internal/dockframemodel.h index 56826fad44559..cf3702d084659 100644 --- a/src/framework/dockwindow/internal/dockframemodel.h +++ b/src/framework/dockwindow/internal/dockframemodel.h @@ -41,6 +41,7 @@ class DockFrameModel : public QObject, public muse::Injectable Q_PROPERTY(QQuickItem * frame READ frame WRITE setFrame NOTIFY frameChanged) Q_PROPERTY(QVariantList tabs READ tabs NOTIFY tabsChanged) + Q_PROPERTY(QQmlComponent * titleBar READ titleBar NOTIFY titleBarChanged) Q_PROPERTY(bool titleBarVisible READ titleBarVisible NOTIFY titleBarVisibleChanged) Q_PROPERTY(bool isHorizontalPanel READ isHorizontalPanel NOTIFY isHorizontalPanelChanged) Q_PROPERTY(QObject * navigationSection READ navigationSection NOTIFY navigationSectionChanged) @@ -58,6 +59,7 @@ class DockFrameModel : public QObject, public muse::Injectable QQuickItem* frame() const; QVariantList tabs() const; + QQmlComponent* titleBar() const; bool titleBarVisible() const; bool isHorizontalPanel() const; QObject* navigationSection() const; @@ -75,6 +77,7 @@ public slots: signals: void frameChanged(QQuickItem* frame); void tabsChanged(); + void titleBarChanged(); void titleBarVisibleChanged(bool visible); void isHorizontalPanelChanged(); void navigationSectionChanged(); @@ -94,7 +97,11 @@ public slots: QObject* currentNavigationSection() const; void updateNavigationSection(); + QQmlComponent* currentTitleBar() const; + void updateTitleBar(); + KDDockWidgets::Frame* m_frame = nullptr; + QQmlComponent* m_titleBar = nullptr; bool m_titleBarVisible = false; bool m_isHorizontalPanel = false; QObject* m_navigationSection = nullptr; diff --git a/src/framework/dockwindow/qml/Muse/Dock/DockFrame.qml b/src/framework/dockwindow/qml/Muse/Dock/DockFrame.qml index 219b5b10d8652..bbe8a99c56f6c 100644 --- a/src/framework/dockwindow/qml/Muse/Dock/DockFrame.qml +++ b/src/framework/dockwindow/qml/Muse/Dock/DockFrame.qml @@ -82,18 +82,22 @@ Rectangle { anchors.top: parent.top + property alias titleBar: frameModel.titleBar + titleBarCpp: root.titleBarCpp contextMenuModel: frameModel.currentDockContextMenuModel visible: frameModel.titleBarVisible isHorizontalPanel: frameModel.isHorizontalPanel - navigation.panel: navPanel - navigation.order: 1 + navigationPanel: navPanel + navigationOrder: 1 onHandleContextMenuItemRequested: function(itemId) { frameModel.handleMenuItem(itemId) } + + titleBarItem: frameModel.titleBar } MouseArea { diff --git a/src/framework/dockwindow/qml/Muse/Dock/DockTitleBar.qml b/src/framework/dockwindow/qml/Muse/Dock/DockTitleBar.qml index 5d17f29313eca..9236988d2a258 100644 --- a/src/framework/dockwindow/qml/Muse/Dock/DockTitleBar.qml +++ b/src/framework/dockwindow/qml/Muse/Dock/DockTitleBar.qml @@ -33,12 +33,13 @@ Item { required property QtObject titleBarCpp - property alias contextMenuModel: contextMenuButton.menuModel - property alias heightWhenVisible: titleBar.heightWhenVisible + property Component titleBarItem: null + property var contextMenuModel: null + property var heightWhenVisible: null + property var navigationPanel: null + property var navigationOrder: null property bool isHorizontalPanel: false - property alias navigation: contextMenuButton.navigation - signal handleContextMenuItemRequested(string itemId) width: parent.width @@ -46,62 +47,93 @@ Item { visible: Boolean(titleBarCpp) - KDDW.TitleBarBase { - id: titleBar - + Loader { + id: titleBarLoader anchors.fill: parent - heightWhenVisible: titleBarContent.implicitHeight - color: ui.theme.backgroundPrimaryColor + property var titleBarCpp: root.titleBarCpp - visible: parent.visible + sourceComponent: root.titleBarItem ?? defaultTitleBarComponent - MouseArea { - id: mouseArea - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: Qt.SizeAllCursor + onLoaded: { + if (titleBarLoader.item) { + item.navigationPanel = Qt.binding(function() { return root.navigationPanel}) + item.navigationOrder = Qt.binding(function() { return root.navigationOrder}) + item.contextMenuModel = Qt.binding(function() { return root.contextMenuModel}) + root.heightWhenVisible = Qt.binding(function() { return item.heightWhenVisible}) + } } + } - Column { - id: titleBarContent + Component { + id: defaultTitleBarComponent + + KDDW.TitleBarBase { + id: titleBar anchors.fill: parent - anchors.leftMargin: 12 - anchors.rightMargin: 12 - spacing: 0 + implicitHeight: titleBarContent.implicitHeight + heightWhenVisible: titleBarContent.implicitHeight + color: ui.theme.backgroundPrimaryColor - RowLayout { - width: parent.width - height: 34 + property var navigationPanel + property var navigationOrder + property var contextMenuModel - StyledTextLabel { - id: titleLabel - Layout.fillWidth: true + visible: parent.visible - text: titleBar.title - font: ui.theme.bodyBoldFont - horizontalAlignment: Qt.AlignLeft - } + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: Qt.SizeAllCursor + } + + Column { + id: titleBarContent - MenuButton { - id: contextMenuButton + anchors.fill: parent + anchors.leftMargin: 12 + anchors.rightMargin: 12 - width: 20 - height: width + spacing: 0 - onHandleMenuItem: function(itemId) { - root.handleContextMenuItemRequested(itemId) + RowLayout { + width: parent.width + height: 34 + + StyledTextLabel { + id: titleLabel + Layout.fillWidth: true + + text: titleBar.title + font: ui.theme.bodyBoldFont + horizontalAlignment: Qt.AlignLeft + } + + MenuButton { + id: contextMenuButton + + width: 20 + height: width + + navigation.panel: root.navigationPanel + navigation.order: root.navigationOrder + menuModel: root.contextMenuModel + + onHandleMenuItem: function(itemId) { + root.handleContextMenuItemRequested(itemId) + } } } - } - SeparatorLine { - id: bottomSeparator - orientation: Qt.Horizontal - anchors.margins: -12 - visible: root.isHorizontalPanel + SeparatorLine { + id: bottomSeparator + orientation: Qt.Horizontal + anchors.margins: -12 + visible: root.isHorizontalPanel + } } } } diff --git a/src/framework/dockwindow/view/dockpanelview.cpp b/src/framework/dockwindow/view/dockpanelview.cpp index 0642220e9285f..51b99f9c4050b 100644 --- a/src/framework/dockwindow/view/dockpanelview.cpp +++ b/src/framework/dockwindow/view/dockpanelview.cpp @@ -164,6 +164,7 @@ DockPanelView::~DockPanelView() dockWidget->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(nullptr)); dockWidget->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(nullptr)); + dockWidget->setProperty(TITLEBAR_PROPERTY, QVariant::fromValue(nullptr)); } QString DockPanelView::groupName() const @@ -194,6 +195,7 @@ void DockPanelView::componentComplete() dockWidget->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(this)); dockWidget->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel)); + dockWidget->setProperty(TITLEBAR_PROPERTY, QVariant::fromValue(m_titleBar)); connect(m_menuModel, &AbstractMenuModel::itemsChanged, [dockWidget, this]() { if (dockWidget) { @@ -222,6 +224,11 @@ AbstractMenuModel* DockPanelView::contextMenuModel() const return m_menuModel->customMenuModel(); } +QQmlComponent* DockPanelView::titleBar() const +{ + return m_titleBar; +} + void DockPanelView::setContextMenuModel(AbstractMenuModel* model) { if (m_menuModel->customMenuModel() == model) { @@ -233,6 +240,16 @@ void DockPanelView::setContextMenuModel(AbstractMenuModel* model) emit contextMenuModelChanged(); } +void DockPanelView::setTitleBar(QQmlComponent* titleBar) +{ + if (m_titleBar == titleBar) { + return; + } + + m_titleBar = titleBar; + emit titleBarChanged(); +} + bool DockPanelView::isTabAllowed(const DockPanelView* tab) const { IF_ASSERT_FAILED(tab) { diff --git a/src/framework/dockwindow/view/dockpanelview.h b/src/framework/dockwindow/view/dockpanelview.h index 8440e456a1bcb..d4431bbd07b29 100644 --- a/src/framework/dockwindow/view/dockpanelview.h +++ b/src/framework/dockwindow/view/dockpanelview.h @@ -41,6 +41,7 @@ class DockPanelView : public DockBase Q_PROPERTY( muse::uicomponents::AbstractMenuModel * contextMenuModel READ contextMenuModel WRITE setContextMenuModel NOTIFY contextMenuModelChanged) + Q_PROPERTY(QQmlComponent * titleBar READ titleBar WRITE setTitleBar NOTIFY titleBarChanged) public: explicit DockPanelView(QQuickItem* parent = nullptr); @@ -49,6 +50,7 @@ class DockPanelView : public DockBase QString groupName() const; QObject* navigationSection() const; uicomponents::AbstractMenuModel* contextMenuModel() const; + QQmlComponent* titleBar() const; bool isTabAllowed(const DockPanelView* tab) const; void addPanelAsTab(DockPanelView* tab); @@ -58,11 +60,13 @@ public slots: void setGroupName(const QString& name); void setNavigationSection(QObject* newNavigation); void setContextMenuModel(uicomponents::AbstractMenuModel* model); + void setTitleBar(QQmlComponent* titleBar); signals: void groupNameChanged(); void navigationSectionChanged(); void contextMenuModelChanged(); + void titleBarChanged(); private: void componentComplete() override; @@ -72,6 +76,7 @@ public slots: class DockPanelMenuModel; DockPanelMenuModel* m_menuModel = nullptr; + QQmlComponent* m_titleBar = nullptr; }; }