diff --git a/src/appshell/qml/NotationPage/NotationPage.qml b/src/appshell/qml/NotationPage/NotationPage.qml
index 5b1c5a3041c56..e3b6b515b7421 100644
--- a/src/appshell/qml/NotationPage/NotationPage.qml
+++ b/src/appshell/qml/NotationPage/NotationPage.qml
@@ -336,6 +336,7 @@ DockPage {
Component.onCompleted: {
mixerPanel.contextMenuModel = contextMenuModel
+ mixerPanel.toolbarComponent = toolbarComponent
}
onResizeRequested: function(newWidth, newHeight) {
diff --git a/src/appshell/qml/dockwindow/DockFrame.qml b/src/appshell/qml/dockwindow/DockFrame.qml
index d75f999926933..10f8bcf5157e8 100644
--- a/src/appshell/qml/dockwindow/DockFrame.qml
+++ b/src/appshell/qml/dockwindow/DockFrame.qml
@@ -112,6 +112,8 @@ Rectangle {
tabsModel: frameModel.tabs
currentIndex: Boolean(root.frameCpp) && root.frameCpp.currentIndex >= 0 ? root.frameCpp.currentIndex : 0
+ currentToolbarComponent: frameModel.currentDockToolbarComponent
+
navigationPanel: navPanel
function setCurrentDockWidget(index: int) {
diff --git a/src/appshell/qml/dockwindow/DockTabBar.qml b/src/appshell/qml/dockwindow/DockTabBar.qml
index b90c16e3e1bd9..673198e3db92f 100644
--- a/src/appshell/qml/dockwindow/DockTabBar.qml
+++ b/src/appshell/qml/dockwindow/DockTabBar.qml
@@ -41,6 +41,8 @@ Rectangle {
property NavigationPanel navigationPanel: null
readonly property string currentItemNavigationName: tabs.currentItem && tabs.currentItem.navigation ? tabs.currentItem.navigation.name : ""
+ property alias currentToolbarComponent: toolbarLoader.sourceComponent
+
signal tabClicked(int index)
signal handleContextMenuItemRequested(string itemId)
@@ -130,7 +132,18 @@ Rectangle {
cursorShape: Qt.SizeAllCursor
}
+ Loader {
+ id: toolbarLoader
+
+ anchors.top: parent.top
+ anchors.left: tabs.right
+ anchors.right: parent.right
+ anchors.bottom: bottomSeparatorContainer.top
+ }
+
Item {
+ id: bottomSeparatorContainer
+
anchors.left: tabs.right
anchors.right: parent.right
anchors.bottom: parent.bottom
diff --git a/src/appshell/view/dockwindow/dockpanelview.cpp b/src/appshell/view/dockwindow/dockpanelview.cpp
index bb905ab3bdc1e..43d74795f5cab 100644
--- a/src/appshell/view/dockwindow/dockpanelview.cpp
+++ b/src/appshell/view/dockwindow/dockpanelview.cpp
@@ -163,6 +163,7 @@ DockPanelView::~DockPanelView()
dockWidget->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(nullptr));
dockWidget->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(nullptr));
+ dockWidget->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(nullptr));
}
QString DockPanelView::groupName() const
@@ -193,12 +194,19 @@ void DockPanelView::componentComplete()
dockWidget->setProperty(DOCK_PANEL_PROPERTY, QVariant::fromValue(this));
dockWidget->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
+ dockWidget->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(m_toolbarComponent));
connect(m_menuModel, &AbstractMenuModel::itemsChanged, [dockWidget, this]() {
if (dockWidget) {
dockWidget->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
}
});
+
+ connect(this, &DockPanelView::toolbarComponentChanged, this, [this, dockWidget]() {
+ if (dockWidget) {
+ dockWidget->setProperty(TOOLBAR_COMPONENT_PROPERTY, QVariant::fromValue(m_toolbarComponent));
+ }
+ });
}
QObject* DockPanelView::navigationSection() const
@@ -221,6 +229,11 @@ AbstractMenuModel* DockPanelView::contextMenuModel() const
return m_menuModel->customMenuModel();
}
+QQmlComponent* DockPanelView::toolbarComponent() const
+{
+ return m_toolbarComponent;
+}
+
void DockPanelView::setContextMenuModel(AbstractMenuModel* model)
{
if (m_menuModel->customMenuModel() == model) {
@@ -232,6 +245,16 @@ void DockPanelView::setContextMenuModel(AbstractMenuModel* model)
emit contextMenuModelChanged();
}
+void DockPanelView::setToolbarComponent(QQmlComponent* component)
+{
+ if (m_toolbarComponent == component) {
+ return;
+ }
+
+ m_toolbarComponent = component;
+ emit toolbarComponentChanged();
+}
+
bool DockPanelView::isTabAllowed(const DockPanelView* tab) const
{
IF_ASSERT_FAILED(tab) {
diff --git a/src/appshell/view/dockwindow/dockpanelview.h b/src/appshell/view/dockwindow/dockpanelview.h
index b14aa66769d7e..ad9715abd4983 100644
--- a/src/appshell/view/dockwindow/dockpanelview.h
+++ b/src/appshell/view/dockwindow/dockpanelview.h
@@ -25,10 +25,10 @@
#include "internal/dockbase.h"
-#include "framework/uicomponents/view/qmllistproperty.h"
-
#include "uicomponents/view/abstractmenumodel.h"
+class QQmlComponent;
+
namespace mu::uicomponents {
class AbstractMenuModel;
}
@@ -43,6 +43,7 @@ class DockPanelView : public DockBase
Q_PROPERTY(
mu::uicomponents::AbstractMenuModel
* contextMenuModel READ contextMenuModel WRITE setContextMenuModel NOTIFY contextMenuModelChanged)
+ Q_PROPERTY(QQmlComponent * toolbarComponent READ toolbarComponent WRITE setToolbarComponent NOTIFY toolbarComponentChanged)
public:
explicit DockPanelView(QQuickItem* parent = nullptr);
@@ -51,6 +52,7 @@ class DockPanelView : public DockBase
QString groupName() const;
QObject* navigationSection() const;
uicomponents::AbstractMenuModel* contextMenuModel() const;
+ QQmlComponent* toolbarComponent() const;
bool isTabAllowed(const DockPanelView* tab) const;
void addPanelAsTab(DockPanelView* tab);
@@ -60,11 +62,13 @@ public slots:
void setGroupName(const QString& name);
void setNavigationSection(QObject* newNavigation);
void setContextMenuModel(uicomponents::AbstractMenuModel* model);
+ void setToolbarComponent(QQmlComponent* component);
signals:
void groupNameChanged();
void navigationSectionChanged();
void contextMenuModelChanged();
+ void toolbarComponentChanged();
private:
void componentComplete() override;
@@ -74,6 +78,8 @@ public slots:
class DockPanelMenuModel;
DockPanelMenuModel* m_menuModel = nullptr;
+
+ QQmlComponent* m_toolbarComponent = nullptr;
};
}
diff --git a/src/appshell/view/dockwindow/docktypes.h b/src/appshell/view/dockwindow/docktypes.h
index 85d347a0e42f5..e0a663841b359 100644
--- a/src/appshell/view/dockwindow/docktypes.h
+++ b/src/appshell/view/dockwindow/docktypes.h
@@ -29,6 +29,7 @@
namespace mu::dock {
inline const char* CONTEXT_MENU_MODEL_PROPERTY("contextMenuModel");
inline const char* DOCK_PANEL_PROPERTY("dockPanel");
+inline const char* TOOLBAR_COMPONENT_PROPERTY("toolbarComponent");
//! NOTE: need to be synchronized with Window shadow(see DockFloatingWindow margins)
inline constexpr int DOCK_WINDOW_SHADOW(8);
diff --git a/src/appshell/view/dockwindow/internal/dockframemodel.cpp b/src/appshell/view/dockwindow/internal/dockframemodel.cpp
index c0c92e86d55c5..1a3e68d2c047f 100644
--- a/src/appshell/view/dockwindow/internal/dockframemodel.cpp
+++ b/src/appshell/view/dockwindow/internal/dockframemodel.cpp
@@ -55,7 +55,8 @@ bool DockFrameModel::eventFilter(QObject* watched, QEvent* event)
return QObject::eventFilter(watched, event);
}
- if (propertyChangeEvent->propertyName() == CONTEXT_MENU_MODEL_PROPERTY) {
+ if (propertyChangeEvent->propertyName() == CONTEXT_MENU_MODEL_PROPERTY
+ || propertyChangeEvent->propertyName() == TOOLBAR_COMPONENT_PROPERTY) {
emit tabsChanged();
if (watched == currentDockWidget()) {
@@ -87,6 +88,7 @@ QVariantList DockFrameModel::tabs() const
QVariantMap tab;
tab["title"] = dock->title();
tab[CONTEXT_MENU_MODEL_PROPERTY] = dock->property(CONTEXT_MENU_MODEL_PROPERTY);
+ tab[TOOLBAR_COMPONENT_PROPERTY] = dock->property(TOOLBAR_COMPONENT_PROPERTY);
result << tab;
}
@@ -204,6 +206,11 @@ QVariant DockFrameModel::currentDockContextMenuModel() const
return currentDockProperty(CONTEXT_MENU_MODEL_PROPERTY);
}
+QVariant DockFrameModel::currentDockToolbarComponent() const
+{
+ return currentDockProperty(TOOLBAR_COMPONENT_PROPERTY);
+}
+
bool DockFrameModel::highlightingVisible() const
{
return highlightingRect().isValid();
diff --git a/src/appshell/view/dockwindow/internal/dockframemodel.h b/src/appshell/view/dockwindow/internal/dockframemodel.h
index e4aa6a5673aad..3427913b96296 100644
--- a/src/appshell/view/dockwindow/internal/dockframemodel.h
+++ b/src/appshell/view/dockwindow/internal/dockframemodel.h
@@ -48,6 +48,7 @@ class DockFrameModel : public QObject
Q_PROPERTY(QObject * navigationSection READ navigationSection NOTIFY navigationSectionChanged)
Q_PROPERTY(QString currentDockUniqueName READ currentDockUniqueName NOTIFY currentDockChanged)
Q_PROPERTY(QVariant currentDockContextMenuModel READ currentDockContextMenuModel NOTIFY currentDockChanged)
+ Q_PROPERTY(QVariant currentDockToolbarComponent READ currentDockToolbarComponent NOTIFY currentDockChanged)
Q_PROPERTY(bool highlightingVisible READ highlightingVisible NOTIFY highlightingVisibleChanged)
Q_PROPERTY(QRect highlightingRect READ highlightingRect NOTIFY highlightingVisibleChanged)
@@ -63,6 +64,7 @@ class DockFrameModel : public QObject
QObject* navigationSection() const;
QString currentDockUniqueName() const;
QVariant currentDockContextMenuModel() const;
+ QVariant currentDockToolbarComponent() const;
bool highlightingVisible() const;
QRect highlightingRect() const;
diff --git a/src/playback/playback.qrc b/src/playback/playback.qrc
index 206c1bcf355bf..34af2d57adbf4 100644
--- a/src/playback/playback.qrc
+++ b/src/playback/playback.qrc
@@ -5,6 +5,7 @@
qml/MuseScore/Playback/internal/MeasureAndBeatFields.qml
qml/MuseScore/Playback/internal/TempoSlider.qml
qml/MuseScore/Playback/MixerPanel.qml
+ qml/MuseScore/Playback/internal/MixerPanelToolbar.qml
qml/MuseScore/Playback/internal/MixerPanelSection.qml
qml/MuseScore/Playback/internal/MixerBalanceSection.qml
qml/MuseScore/Playback/internal/MixerVolumeSection.qml
diff --git a/src/playback/qml/MuseScore/Playback/MixerPanel.qml b/src/playback/qml/MuseScore/Playback/MixerPanel.qml
index 8660d4b5885ff..31972520d593f 100644
--- a/src/playback/qml/MuseScore/Playback/MixerPanel.qml
+++ b/src/playback/qml/MuseScore/Playback/MixerPanel.qml
@@ -34,6 +34,10 @@ ColumnLayout {
id: root
property alias contextMenuModel: contextMenuModel
+ property Component toolbarComponent: MixerPanelToolbar {
+ navigation.section: root.navigationSection
+ navigation.order: 1
+ }
property NavigationSection navigationSection: null
property NavigationPanel navigationPanel: mixerPanelModel.count > 0 ? mixerPanelModel.get(0).channelItem.panel : null // first panel
diff --git a/src/playback/qml/MuseScore/Playback/internal/MixerPanelToolbar.qml b/src/playback/qml/MuseScore/Playback/internal/MixerPanelToolbar.qml
new file mode 100644
index 0000000000000..cd421aa752e04
--- /dev/null
+++ b/src/playback/qml/MuseScore/Playback/internal/MixerPanelToolbar.qml
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-only
+ * MuseScore-CLA-applies
+ *
+ * MuseScore
+ * Music Composition & Notation
+ *
+ * Copyright (C) 2023 MuseScore BVBA and others
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * 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 .
+ */
+import QtQuick 2.15
+
+import MuseScore.Ui 1.0
+import MuseScore.UiComponents 1.0
+
+Item {
+ id: root
+
+ property alias navigation: navPanel
+
+ anchors.fill: parent
+
+ NavigationPanel {
+ id: navPanel
+ name: "MixerPanelToolbarPanel"
+ enabled: root.enabled && root.visible
+ }
+
+ FlatButton {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: 2
+
+ icon: IconCode.SETTINGS_COG
+ text: qsTrc("playback", "Customize mixer")
+ orientation: Qt.Horizontal
+
+ navigation.panel: navPanel
+ navigation.row: 0
+ }
+}