Merge pull request #8997 from RomanPudashkin/standard_context_menu

[MU4] Standard context menu
This commit is contained in:
Elnur Ismailzada 2021-09-02 10:04:29 +02:00 committed by GitHub
commit 20db01e728
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 868 additions and 734 deletions

View file

@ -30,7 +30,6 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/appshellmodule.h
${CMAKE_CURRENT_LIST_DIR}/appshell.cpp
${CMAKE_CURRENT_LIST_DIR}/appshell.h
${CMAKE_CURRENT_LIST_DIR}/inotationpagestate.h
${CMAKE_CURRENT_LIST_DIR}/commandlinecontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/commandlinecontroller.h
${CMAKE_CURRENT_LIST_DIR}/iappshellconfiguration.h
@ -43,8 +42,6 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/internal/applicationactioncontroller.h
${CMAKE_CURRENT_LIST_DIR}/internal/appshellconfiguration.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/appshellconfiguration.h
${CMAKE_CURRENT_LIST_DIR}/internal/notationpagestate.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/notationpagestate.h
${CMAKE_CURRENT_LIST_DIR}/internal/framelesswindowcontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/framelesswindowcontroller.h
${CMAKE_CURRENT_LIST_DIR}/internal/istartupscenario.h

View file

@ -32,7 +32,6 @@
#include "internal/applicationuiactions.h"
#include "internal/applicationactioncontroller.h"
#include "internal/appshellconfiguration.h"
#include "internal/notationpagestate.h"
#include "internal/startupscenario.h"
#include "view/devtools/settingslistmodel.h"
@ -68,7 +67,6 @@ using namespace mu::dock;
static std::shared_ptr<ApplicationActionController> s_applicationActionController = std::make_shared<ApplicationActionController>();
static std::shared_ptr<ApplicationUiActions> s_applicationUiActions = std::make_shared<ApplicationUiActions>(s_applicationActionController);
static std::shared_ptr<AppShellConfiguration> s_appShellConfiguration = std::make_shared<AppShellConfiguration>();
static std::shared_ptr<NotationPageState> s_notationPageState = std::make_shared<NotationPageState>();
static void appshell_init_qrc()
{
@ -89,7 +87,6 @@ void AppShellModule::registerExports()
DockSetup::registerExports();
ioc()->registerExport<IAppShellConfiguration>(moduleName(), s_appShellConfiguration);
ioc()->registerExport<INotationPageState>(moduleName(), s_notationPageState);
ioc()->registerExport<IStartupScenario>(moduleName(), new StartupScenario());
}
@ -147,8 +144,9 @@ void AppShellModule::registerUiTypes()
void AppShellModule::onInit(const IApplication::RunMode&)
{
DockSetup::onInit();
s_appShellConfiguration->init();
s_applicationActionController->init();
s_notationPageState->init();
s_applicationUiActions->init();
}

View file

@ -23,28 +23,31 @@
#ifndef MU_APPSHELL_APPSHELLTYPES_H
#define MU_APPSHELL_APPSHELLTYPES_H
#include <QString>
namespace mu::appshell {
enum class PanelType
{
Undefined = 0,
Palettes,
Instruments,
Inspector,
NotationToolBar,
NoteInputBar,
UndoRedoToolBar,
NotationNavigator,
NotationStatusBar,
PlaybackToolBar,
Mixer,
Timeline,
Synthesizer,
SelectionFilter,
Piano,
ComparisonTool,
DrumsetPanel
};
using PanelTypeList = std::vector<PanelType>;
using DockName = QString;
// Panels:
static const DockName PALETTES_PANEL_NAME("palettesPanel");
static const DockName INSTRUMENTS_PANEL_NAME("instrumentsPanel");
static const DockName INSPECTOR_PANEL_NAME("inspectorPanel");
static const DockName NOTATION_NAVIGATOR_PANEL_NAME("notationNavigatorPanel");
static const DockName TIMELINE_PANEL_NAME("timelinePanel");
static const DockName MIXER_PANEL_NAME("mixerPanel");
static const DockName SYNTHESIZER_PANEL_NAME("synthesizerPanel");
static const DockName SELECTION_FILTERS_PANEL_NAME("selectionFiltersPanel");
static const DockName PIANO_PANEL_NAME("pianoPanel");
static const DockName DRUMSET_PANEL_NAME("drumsetPanel");
// Toolbars:
static const DockName NOTATION_TOOLBAR_NAME("notationToolBar");
static const DockName UNDO_REDO_TOOLBAR_NAME("undoRedoToolBar");
static const DockName NOTE_INPUT_BAR_NAME("noteInputBar");
static const DockName PLAYBACK_TOOLBAR_NAME("playbackToolBar");
// Other:
static const DockName NOTATION_STATUSBAR_NAME("notationStatusBar");
enum class StartupSessionType
{

View file

@ -24,10 +24,16 @@
#include "ui/view/iconcodes.h"
#include "context/uicontext.h"
#include "view/dockwindow/idockwindow.h"
#include "log.h"
using namespace mu::appshell;
using namespace mu::ui;
using namespace mu::actions;
using namespace mu::dock;
const ActionCode TOGGLE_NAVIGATOR_ACTION_CODE("toggle-navigator");
const UiActionList ApplicationUiActions::m_actions = {
UiAction("quit",
@ -178,24 +184,6 @@ const UiActionList ApplicationUiActions::m_actions = {
)
};
const std::vector<std::pair<mu::actions::ActionCode, PanelType> > ApplicationUiActions::m_panels = {
{ "toggle-palettes", PanelType::Palettes },
{ "toggle-instruments", PanelType::Instruments },
{ "inspector", PanelType::Inspector },
{ "toggle-selection-filter", PanelType::SelectionFilter },
{ "toggle-notationtoolbar", PanelType::NotationToolBar },
{ "toggle-noteinput", PanelType::NoteInputBar },
{ "toggle-undoredo", PanelType::UndoRedoToolBar },
{ "toggle-navigator", PanelType::NotationNavigator },
{ "toggle-statusbar", PanelType::NotationStatusBar },
{ "toggle-transport", PanelType::PlaybackToolBar },
{ "toggle-mixer", PanelType::Mixer },
{ "toggle-timeline", PanelType::Timeline },
{ "synth-control", PanelType::Synthesizer },
{ "toggle-piano", PanelType::Piano },
{ "toggle-scorecmp-tool", PanelType::ComparisonTool }
};
ApplicationUiActions::ApplicationUiActions(std::shared_ptr<ApplicationActionController> controller)
: m_controller(controller)
{
@ -203,16 +191,34 @@ ApplicationUiActions::ApplicationUiActions(std::shared_ptr<ApplicationActionCont
void ApplicationUiActions::init()
{
notationPageState()->panelsVisibleChanged().onReceive(this, [this](const PanelTypeList& types) {
actions::ActionCodeList alist;
for (PanelType t : types) {
actions::ActionCode code = panelTypeToAction(t);
if (!code.empty()) {
alist.push_back(std::move(code));
configuration()->isNotationNavigatorVisibleChanged().onNotify(this, [this]() {
m_actionCheckedChanged.send({ TOGGLE_NAVIGATOR_ACTION_CODE });
});
dockWindowProvider()->windowChanged().onNotify(this, [this]() {
listenOpenedDocksChanged(dockWindowProvider()->window());
});
}
void ApplicationUiActions::listenOpenedDocksChanged(IDockWindow* window)
{
if (!window) {
return;
}
window->docksOpenStatusChanged().onReceive(this, [this](const QStringList& dockNames) {
ActionCodeList actions;
for (const ActionCode& toggleDockAction : toggleDockActions().keys()) {
const DockName& dockName = toggleDockActions()[toggleDockAction];
if (dockNames.contains(dockName)) {
actions.push_back(toggleDockAction);
}
}
if (!alist.empty()) {
m_actionCheckedChanged.send(alist);
if (!actions.empty()) {
m_actionCheckedChanged.send(actions);
}
});
}
@ -231,34 +237,21 @@ bool ApplicationUiActions::actionEnabled(const UiAction& act) const
return true;
}
PanelType ApplicationUiActions::panelType(const actions::ActionCode& code) const
{
for (const auto& p : m_panels) {
if (p.first == code) {
return p.second;
}
}
return PanelType::Undefined;
}
mu::actions::ActionCode ApplicationUiActions::panelTypeToAction(const PanelType& type) const
{
for (const auto& p : m_panels) {
if (p.second == type) {
return p.first;
}
}
return actions::ActionCode();
}
bool ApplicationUiActions::actionChecked(const UiAction& act) const
{
PanelType panel = panelType(act.code);
if (panel != PanelType::Undefined) {
return notationPageState()->isPanelVisible(panel);
QMap<ActionCode, DockName> toggleDockActions = ApplicationUiActions::toggleDockActions();
DockName dockName = toggleDockActions.value(act.code, DockName());
if (dockName.isEmpty()) {
return false;
}
return false;
if (dockName == NOTATION_NAVIGATOR_PANEL_NAME) {
return configuration()->isNotationNavigatorVisible();
}
const IDockWindow* window = dockWindowProvider()->window();
return window ? window->isDockOpen(dockName) : false;
}
mu::async::Channel<mu::actions::ActionCodeList> ApplicationUiActions::actionEnabledChanged() const
@ -270,3 +263,23 @@ mu::async::Channel<mu::actions::ActionCodeList> ApplicationUiActions::actionChec
{
return m_actionCheckedChanged;
}
const QMap<mu::actions::ActionCode, DockName>& ApplicationUiActions::toggleDockActions()
{
static const QMap<mu::actions::ActionCode, DockName> actionsMap {
{ TOGGLE_NAVIGATOR_ACTION_CODE, NOTATION_NAVIGATOR_PANEL_NAME },
{ "toggle-mixer", MIXER_PANEL_NAME },
{ "toggle-timeline", TIMELINE_PANEL_NAME },
{ "toggle-palettes", PALETTES_PANEL_NAME },
{ "toggle-instruments", INSTRUMENTS_PANEL_NAME },
{ "inspector", INSPECTOR_PANEL_NAME },
{ "toggle-selection-filter", SELECTION_FILTERS_PANEL_NAME },
{ "toggle-statusbar", NOTATION_STATUSBAR_NAME },
{ "toggle-noteinput", NOTE_INPUT_BAR_NAME },
{ "toggle-notationtoolbar", NOTATION_TOOLBAR_NAME },
{ "toggle-undoredo", UNDO_REDO_TOOLBAR_NAME },
{ "toggle-transport", PLAYBACK_TOOLBAR_NAME }
};
return actionsMap;
}

View file

@ -26,15 +26,17 @@
#include "applicationactioncontroller.h"
#include "modularity/ioc.h"
#include "context/iuicontextresolver.h"
#include "inotationpagestate.h"
#include "async/asyncable.h"
#include "view/dockwindow/idockwindowprovider.h"
namespace mu::appshell {
class ApplicationUiActions : public ui::IUiActionsModule, public async::Asyncable
{
INJECT(appshell, INotationPageState, notationPageState)
public:
INJECT(appshell, dock::IDockWindowProvider, dockWindowProvider)
INJECT(appshell, IAppShellConfiguration, configuration)
public:
ApplicationUiActions(std::shared_ptr<ApplicationActionController> controller);
void init();
@ -47,13 +49,12 @@ public:
bool actionChecked(const ui::UiAction& act) const override;
async::Channel<actions::ActionCodeList> actionCheckedChanged() const override;
private:
static const QMap<actions::ActionCode, DockName>& toggleDockActions();
PanelType panelType(const actions::ActionCode& code) const;
actions::ActionCode panelTypeToAction(const PanelType& type) const;
private:
void listenOpenedDocksChanged(dock::IDockWindow* window);
static const ui::UiActionList m_actions;
static const std::vector<std::pair<actions::ActionCode, PanelType> > m_panels;
std::shared_ptr<ApplicationActionController> m_controller;
async::Channel<actions::ActionCodeList> m_actionEnabledChanged;

View file

@ -1,103 +0,0 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*/
#include "notationpagestate.h"
using namespace mu::appshell;
void NotationPageState::init()
{
configuration()->isNotationNavigatorVisibleChanged().onNotify(this, [this]() {
m_panelsVisibleChanged.send({ PanelType::NotationNavigator });
});
}
bool NotationPageState::isPanelVisible(PanelType type) const
{
switch (type) {
case PanelType::Palettes:
case PanelType::Instruments:
case PanelType::Inspector:
case PanelType::SelectionFilter:
case PanelType::NotationToolBar:
case PanelType::NoteInputBar:
case PanelType::UndoRedoToolBar:
case PanelType::PlaybackToolBar:
case PanelType::NotationStatusBar:
case PanelType::Mixer:
case PanelType::Timeline:
case PanelType::DrumsetPanel:
return m_panelVisibleMap[type];
case PanelType::NotationNavigator:
return configuration()->isNotationNavigatorVisible();
case PanelType::Synthesizer:
case PanelType::Piano:
case PanelType::ComparisonTool:
case PanelType::Undefined:
return false;
}
return false;
}
void NotationPageState::setIsPanelsVisible(const std::map<PanelType, bool>& panelsVisible)
{
PanelTypeList changedTypes;
for (const auto& type: panelsVisible) {
setIsPanelVisible(type.first, type.second);
changedTypes.push_back(type.first);
}
m_panelsVisibleChanged.send(changedTypes);
}
mu::async::Channel<PanelTypeList> NotationPageState::panelsVisibleChanged() const
{
return m_panelsVisibleChanged;
}
void NotationPageState::setIsPanelVisible(PanelType type, bool visible)
{
switch (type) {
case PanelType::Palettes:
case PanelType::Instruments:
case PanelType::Inspector:
case PanelType::SelectionFilter:
case PanelType::NotationToolBar:
case PanelType::NoteInputBar:
case PanelType::UndoRedoToolBar:
case PanelType::PlaybackToolBar:
case PanelType::NotationStatusBar:
case PanelType::Mixer:
case PanelType::Timeline:
case PanelType::DrumsetPanel:
m_panelVisibleMap[type] = visible;
break;
case PanelType::NotationNavigator:
configuration()->setIsNotationNavigatorVisible(visible);
break;
case PanelType::Piano:
case PanelType::ComparisonTool:
case PanelType::Synthesizer:
case PanelType::Undefined:
break;
}
}

View file

@ -108,7 +108,7 @@ ListView {
navigation: radioButtonDelegate.navigation
onHandleMenuItem: {
Qt.callLater(appMenuModel.handleMenuItem, item.id)
Qt.callLater(appMenuModel.handleMenuItem, itemId)
}
}
}

View file

@ -25,7 +25,6 @@ import QtQuick.Controls 2.15
import MuseScore.Ui 1.0
import MuseScore.Shortcuts 1.0
import MuseScore.AppShell 1.0
import MuseScore.Dock 1.0
ApplicationWindow {
id: root

View file

@ -314,7 +314,7 @@ Rectangle {
id: menuLoader
onHandleMenuItem: {
console.log("selected " + item.id)
console.log("selected " + itemId)
}
}
}

View file

@ -106,7 +106,7 @@ StyledDialogView {
id: menuLoader
onHandleMenuItem: {
console.log("selected " + item.id)
console.log("selected " + itemId)
}
}
}

View file

@ -41,8 +41,6 @@ DockPage {
objectName: "Notation"
uri: "musescore://notation"
property DockWindow dockWindow: null
property var topToolKeyNavSec
property NotationPageModel pageModel: NotationPageModel {}
@ -73,21 +71,7 @@ DockPage {
}
onInited: {
pageModel.setNotationToolBarDockName(notationToolBar.objectName)
pageModel.setPlaybackToolBarDockName(playbackToolBar.objectName)
pageModel.setUndoRedoToolBarDockName(undoRedoToolBar.objectName)
pageModel.setNoteInputBarDockName(noteInputBar.objectName)
pageModel.setPalettesPanelDockName(palettesPanel.objectName)
pageModel.setInspectorPanelDockName(inspectorPanel.objectName)
pageModel.setInstrumentsPanelDockName(instrumentsPanel.objectName)
pageModel.setSelectionFilterPanelDockName(selectionFilterPanel.objectName)
pageModel.setPianoRollDockName(pianoRollPanel.objectName)
pageModel.setMixerDockName(mixerPanel.objectName)
pageModel.setTimelineDockName(timelinePanel.objectName)
pageModel.setDrumsetPanelDockName(drumsetPanel.objectName)
pageModel.setStatusBarDockName(notationStatusBar.objectName)
Qt.callLater(pageModel.init, root.dockWindow)
Qt.callLater(pageModel.init)
}
readonly property int defaultPanelWidth: 300
@ -117,7 +101,7 @@ DockPage {
DockToolBar {
id: playbackToolBar
objectName: "playbackToolBar"
objectName: pageModel.playbackToolBarName()
title: qsTrc("appshell", "Playback controls")
width: root.width / 3
@ -133,9 +117,7 @@ DockPage {
},
DockToolBar {
id: undoRedoToolBar
objectName: "undoRedoToolBar"
objectName: pageModel.undoRedoToolBarName()
title: qsTrc("appshell", "Undo/redo toolbar")
minimumWidth: 74
@ -154,7 +136,7 @@ DockPage {
DockToolBar {
id: noteInputBar
objectName: "noteInputBar"
objectName: pageModel.noteInputBarName()
title: qsTrc("appshell", "Note input")
horizontalPreferredSize: Qt.size(720, root.toolBarHeight)
@ -175,7 +157,7 @@ DockPage {
DockPanel {
id: palettesPanel
objectName: "palettesPanel"
objectName: pageModel.palettesPanelName()
title: qsTrc("appshell", "Palettes")
navigationSection: root.navigationPanelSec(palettesPanel.location)
@ -194,7 +176,7 @@ DockPage {
DockPanel {
id: instrumentsPanel
objectName: "instrumentsPanel"
objectName: pageModel.instrumentsPanelName()
title: qsTrc("appshell", "Instruments")
navigationSection: root.navigationPanelSec(instrumentsPanel.location)
@ -208,8 +190,8 @@ DockPage {
InstrumentsPanel {
navigationSection: instrumentsPanel.navigationSection
onContextMenuModelChanged: {
instrumentsPanel.contextMenuModel = newModel
Component.onCompleted: {
instrumentsPanel.contextMenuModel = contextMenuModel
}
}
},
@ -217,7 +199,7 @@ DockPage {
DockPanel {
id: inspectorPanel
objectName: "inspectorPanel"
objectName: pageModel.inspectorPanelName()
title: qsTrc("appshell", "Properties")
navigationSection: root.navigationPanelSec(inspectorPanel.location)
@ -236,7 +218,7 @@ DockPage {
DockPanel {
id: selectionFilterPanel
objectName: "selectionFilterPanel"
objectName: pageModel.selectionFiltersPanelName()
title: qsTrc("appshell", "Selection Filter")
navigationSection: root.navigationPanelSec(selectionFilterPanel.location)
@ -261,7 +243,7 @@ DockPage {
DockPanel {
id: mixerPanel
objectName: "mixerPanel"
objectName: pageModel.mixerPanelName()
title: qsTrc("appshell", "Mixer")
allowedAreas: Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea
@ -285,7 +267,7 @@ DockPage {
DockPanel {
id: pianoRollPanel
objectName: "pianoRollPanel"
objectName: pageModel.pianoPanelName()
title: qsTrc("appshell", "Piano Roll")
allowedAreas: Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea
@ -314,7 +296,7 @@ DockPage {
DockPanel {
id: timelinePanel
objectName: "timelinePanel"
objectName: pageModel.timelinePanelName()
title: qsTrc("appshell", "Timeline")
allowedAreas: Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea
@ -335,7 +317,7 @@ DockPage {
DockPanel {
id: drumsetPanel
objectName: "drumsetPanel"
objectName: pageModel.drumsetPanelName()
title: qsTrc("appshell", "Drumset Tools")
allowedAreas: Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea
@ -362,7 +344,7 @@ DockPage {
statusBar: DockStatusBar {
id: notationStatusBar
objectName: "notationStatusBar"
objectName: pageModel.statusBarName()
NotationStatusBar {}
}

View file

@ -205,7 +205,7 @@ Rectangle {
}
onHandleMenuItem: {
switch (item.id) {
switch (itemId) {
case model.concertPitchAction.id:
model.handleAction(model.concertPitchAction.code)
break

View file

@ -94,8 +94,6 @@ DockWindow {
HomePage {},
NotationPage {
dockWindow: root
topToolKeyNavSec: root.topToolKeyNavSec
},

View file

@ -86,7 +86,7 @@ Rectangle {
visible: frameModel.titleBarVisible
onHandleContextMenuItemRequested: {
frameModel.handleMenuItem(item)
frameModel.handleMenuItem(itemId)
}
}
@ -167,7 +167,7 @@ Rectangle {
}
onHandleContextMenuItemRequested: {
frameModel.handleMenuItem(item)
frameModel.handleMenuItem(itemId)
}
}
}

View file

@ -31,7 +31,7 @@ StyledTabButton {
property alias contextMenuModel: contextMenuButton.menuModel
signal handleContextMenuItemRequested(var item)
signal handleContextMenuItemRequested(string itemId)
height: 36
width: implicitWidth
@ -63,8 +63,8 @@ StyledTabButton {
navigation.panel: root.navigation.panel
navigation.order: root.navigation.order + 1
onHandleMenuItem: function(item) {
root.handleContextMenuItemRequested(item)
onHandleMenuItem: function(itemId) {
root.handleContextMenuItemRequested(itemId)
}
}
}

View file

@ -36,7 +36,7 @@ Item {
property alias contextMenuModel: contextMenuButton.menuModel
property alias heightWhenVisible: titleBar.heightWhenVisible
signal handleContextMenuItemRequested(var item)
signal handleContextMenuItemRequested(string itemId)
width: parent.width
height: visible ? heightWhenVisible : 0
@ -73,8 +73,8 @@ Item {
Layout.margins: 2
onHandleMenuItem: function(item) {
root.handleContextMenuItemRequested(item)
onHandleMenuItem: function(itemId) {
root.handleContextMenuItemRequested(itemId)
}
}
}

View file

@ -221,6 +221,22 @@ void DockPage::setDockOpen(const QString& dockName, bool open)
}
}
bool DockPage::isDockFloating(const QString& dockName) const
{
const DockBase* dock = dockByName(dockName);
return dock ? dock->floating() : false;
}
void DockPage::toggleDockFloating(const QString& dockName)
{
DockBase* dock = dockByName(dockName);
if (!dock) {
return;
}
dock->setFloating(!dock->floating());
}
void DockPage::setUri(const QString& uri)
{
if (uri == m_uri) {

View file

@ -81,6 +81,9 @@ public:
void toggleDock(const QString& dockName);
void setDockOpen(const QString& dockName, bool open);
bool isDockFloating(const QString& dockName) const;
void toggleDockFloating(const QString& dockName);
public slots:
void setUri(const QString& uri);
void setCentralDock(DockCentral* central);

View file

@ -26,8 +26,8 @@
#include "log.h"
#include "translation.h"
#include "ui/uitypes.h"
#include "ui/uitypes.h"
#include "ui/view/abstractmenumodel.h"
using namespace mu::dock;
@ -35,65 +35,69 @@ using namespace mu::uicomponents;
using namespace mu::ui;
using namespace mu::actions;
class DockPanel::DockPanelMenuModel : public ui::AbstractMenuModel
class DockPanel::DockPanelMenuModel : public AbstractMenuModel
{
public:
explicit DockPanelMenuModel(QObject* parent = nullptr)
: AbstractMenuModel(parent)
DockPanelMenuModel(DockPanel* panel)
: AbstractMenuModel(panel), m_panel(panel)
{
connect(m_panel, &DockPanel::floatingChanged, this, [this]() {
load();
});
}
void load() override
{
//! TODO: temporary solution for testing
MenuItem close;
close.code = "close";
close.title = "Close tab";
close.state.enabled = true;
TRACEFUNC;
MenuItem undock;
undock.code = "undock";
undock.title = "Undock";
undock.state.enabled = true;
MenuItemList items;
MenuItem move;
move.code = "move";
move.title = "Move panel to right side";
move.state.enabled = true;
if (m_customMenuModel && m_customMenuModel->rowCount() > 0) {
items << m_customMenuModel->items();
items << makeSeparator();
}
MenuItemList standardItems {
close,
undock,
move
};
MenuItem closeDockItem;
closeDockItem.id = "set-dock-open";
closeDockItem.code = codeFromQString(closeDockItem.id);
closeDockItem.title = mu::qtrc("dock", "Close");
closeDockItem.state.enabled = true;
closeDockItem.args = ActionData::make_arg2<QString, bool>(m_panel->objectName(), false);
items << closeDockItem;
setItems(standardItems);
MenuItem toggleFloatingItem;
toggleFloatingItem.id = "toggle-floating";
toggleFloatingItem.code = codeFromQString(toggleFloatingItem.id);
toggleFloatingItem.title = m_panel->floating() ? mu::qtrc("dock", "Dock")
: mu::qtrc("dock", "Undock");
toggleFloatingItem.state.enabled = true;
toggleFloatingItem.args = ActionData::make_arg1<QString>(m_panel->objectName());
items << toggleFloatingItem;
setItems(items);
}
QVariant customMenuModel() const
AbstractMenuModel* customMenuModel() const
{
return m_customMenuModel;
}
void setCustomMenuModel(const QVariant& model)
void setCustomMenuModel(AbstractMenuModel* model)
{
m_customMenuModel = model;
}
QVariant toVariant() const
{
QVariantList result = m_customMenuModel.toList();
if (!result.isEmpty()) {
result << makeSeparator().toMap();
if (!model) {
return;
}
result << itemsProperty();
return result;
connect(model, &AbstractMenuModel::itemsChanged, this, [this]() {
load();
});
}
private:
QVariant m_customMenuModel;
AbstractMenuModel* m_customMenuModel = nullptr;
DockPanel* m_panel = nullptr;
};
DockPanel::DockPanel(QQuickItem* parent)
@ -110,6 +114,7 @@ DockPanel::~DockPanel()
}
w->setProperty(DOCK_PANEL_PROPERY, QVariant::fromValue(nullptr));
w->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(nullptr));
}
DockPanel* DockPanel::tabifyPanel() const
@ -144,11 +149,11 @@ void DockPanel::componentComplete()
m_menuModel->load();
w->setProperty(DOCK_PANEL_PROPERY, QVariant::fromValue(this));
w->setProperty(CONTEXT_MENU_MODEL_PROPERTY, m_menuModel->toVariant());
w->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
connect(this, &DockPanel::contextMenuModelChanged, [this, w]() {
connect(m_menuModel, &AbstractMenuModel::itemsChanged, [w, this]() {
if (w) {
w->setProperty(CONTEXT_MENU_MODEL_PROPERTY, m_menuModel->toVariant());
w->setProperty(CONTEXT_MENU_MODEL_PROPERTY, QVariant::fromValue(m_menuModel));
}
});
}
@ -168,12 +173,12 @@ void DockPanel::setNavigationSection(QObject* newNavigation)
emit navigationSectionChanged();
}
QVariant DockPanel::contextMenuModel() const
AbstractMenuModel* DockPanel::contextMenuModel() const
{
return m_menuModel->customMenuModel();
}
void DockPanel::setContextMenuModel(const QVariant& model)
void DockPanel::setContextMenuModel(AbstractMenuModel* model)
{
if (m_menuModel->customMenuModel() == model) {
return;

View file

@ -27,15 +27,20 @@
#include "framework/uicomponents/view/qmllistproperty.h"
#include "ui/view/abstractmenumodel.h"
namespace mu::ui {
class AbstractMenuModel;
}
namespace mu::dock {
class DockPanel : public DockBase
{
Q_OBJECT
Q_PROPERTY(DockPanel * tabifyPanel READ tabifyPanel WRITE setTabifyPanel NOTIFY tabifyPanelChanged)
Q_PROPERTY(QObject * navigationSection READ navigationSection WRITE setNavigationSection NOTIFY navigationSectionChanged)
Q_PROPERTY(QVariant contextMenuModel READ contextMenuModel WRITE setContextMenuModel NOTIFY contextMenuModelChanged)
Q_PROPERTY(mu::ui::AbstractMenuModel* contextMenuModel READ contextMenuModel WRITE setContextMenuModel NOTIFY contextMenuModelChanged)
public:
explicit DockPanel(QQuickItem* parent = nullptr);
@ -43,12 +48,12 @@ public:
DockPanel* tabifyPanel() const;
QObject* navigationSection() const;
QVariant contextMenuModel() const;
ui::AbstractMenuModel* contextMenuModel() const;
public slots:
void setTabifyPanel(DockPanel* panel);
void setNavigationSection(QObject* newNavigation);
void setContextMenuModel(const QVariant& model);
void setContextMenuModel(ui::AbstractMenuModel* model);
signals:
void tabifyPanelChanged(DockPanel* panel);

View file

@ -25,6 +25,8 @@
#include "internal/dropindicators.h"
#include "internal/dockseparator.h"
#include "internal/dockframemodel.h"
#include "internal/dockwindowactionscontroller.h"
#include "internal/dockwindowprovider.h"
#include "dockwindow.h"
#include "dockpanel.h"
@ -34,12 +36,6 @@
#include "dockcentral.h"
#include "dockpage.h"
#ifdef Q_OS_MAC
#include "internal/platform/macos/macosmainwindowprovider.h"
#else
#include "mainwindowprovider.h"
#endif
#include "docktypes.h"
#include "thirdparty/KDDockWidgets/src/Config.h"
@ -81,6 +77,9 @@ public:
}
using namespace mu::dock;
using namespace mu::modularity;
static std::shared_ptr<DockWindowActionsController> s_actionsController = std::make_shared<DockWindowActionsController>();
void DockSetup::registerQmlTypes()
{
@ -95,17 +94,12 @@ void DockSetup::registerQmlTypes()
qmlRegisterType<DockFrameModel>("MuseScore.Dock", 1, 0, "DockFrameModel");
qmlRegisterType<DockBase>("MuseScore.Dock", 1, 0, "DockBase");
#ifdef Q_OS_MAC
qmlRegisterType<MacOSMainWindowProvider>("MuseScore.Dock", 1, 0, "MainWindowProvider");
#else
qmlRegisterType<MainWindowProvider>("MuseScore.Dock", 1, 0, "MainWindowProvider");
#endif
qRegisterMetaType<DropIndicators*>();
}
void DockSetup::registerExports()
{
ioc()->registerExport<IDockWindowProvider>("dock", new DockWindowProvider());
}
void DockSetup::setup(QQmlEngine* engine)
@ -133,3 +127,8 @@ void DockSetup::setup(QQmlEngine* engine)
KDDockWidgets::Config::self().setSeparatorThickness(1);
}
void DockSetup::onInit()
{
s_actionsController->init();
}

View file

@ -32,6 +32,7 @@ public:
static void registerQmlTypes();
static void registerExports();
static void setup(QQmlEngine* engine);
static void onInit();
};
}

View file

@ -22,29 +22,14 @@ set (DOCK_LIBS
kddockwidgets
)
if (OS_IS_MAC)
set (DOCKWINDOW_PLATFORM_SRC
${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosmainwindowprovider.mm
${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosmainwindowprovider.h
)
# Don't mix C++ and Objective-C++ in Unity Build
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosmainwindowprovider.mm
PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosmainwindowprovider.mm
PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
else()
set (DOCKWINDOW_PLATFORM_SRC )
endif()
set (DOCKWINDOW_SRC
${CMAKE_CURRENT_LIST_DIR}/docksetup.cpp
${CMAKE_CURRENT_LIST_DIR}/docksetup.h
${CMAKE_CURRENT_LIST_DIR}/docktypes.h
${CMAKE_CURRENT_LIST_DIR}/dockwindow.cpp
${CMAKE_CURRENT_LIST_DIR}/dockwindow.h
${CMAKE_CURRENT_LIST_DIR}/mainwindowprovider.cpp
${CMAKE_CURRENT_LIST_DIR}/mainwindowprovider.h
${CMAKE_CURRENT_LIST_DIR}/idockwindow.h
${CMAKE_CURRENT_LIST_DIR}/idockwindowprovider.h
${CMAKE_CURRENT_LIST_DIR}/dockpage.cpp
${CMAKE_CURRENT_LIST_DIR}/dockpage.h
${CMAKE_CURRENT_LIST_DIR}/dockpanel.cpp
@ -69,6 +54,10 @@ set (DOCKWINDOW_SRC
${CMAKE_CURRENT_LIST_DIR}/internal/dockseparator.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockframemodel.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dockframemodel.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockwindowactionscontroller.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dockwindowactionscontroller.h
${CMAKE_CURRENT_LIST_DIR}/internal/dockwindowprovider.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/dockwindowprovider.h
${DOCKWINDOW_PLATFORM_SRC}
)

View file

@ -38,6 +38,7 @@
#include "log.h"
using namespace mu::dock;
using namespace mu::async;
static constexpr double MAX_DISTANCE_TO_HOLDER = 25;
@ -48,6 +49,11 @@ DockWindow::DockWindow(QQuickItem* parent)
{
}
DockWindow::~DockWindow()
{
dockWindowProvider()->deinit();
}
void DockWindow::componentComplete()
{
TRACEFUNC;
@ -60,78 +66,13 @@ void DockWindow::componentComplete()
connect(qApp, &QCoreApplication::aboutToQuit, this, &DockWindow::onQuit);
configuration()->windowGeometryChanged().onNotify(this, [this]() {
if (m_quiting) {
return;
}
resetWindowState();
});
mainWindow()->changeToolBarOrientationRequested().onReceive(this, [this](QString name, mu::framework::Orientation orientation) {
const DockPage* page = currentPage();
DockToolBar* toolBar = page ? dynamic_cast<DockToolBar*>(page->dockByName(name)) : nullptr;
if (toolBar) {
toolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
uiConfiguration()->windowGeometryChanged().onNotify(this, [this]() {
if (!m_quiting) {
resetWindowState();
}
});
mainWindow()->hideAllDockingHoldersRequested().onNotify(this, [this]() {
hideCurrentToolBarDockingHolder();
hideCurrentPanelDockingHolder();
});
mainWindow()->showToolBarDockingHolderRequested().onReceive(this, [this](const QPoint& mouseGlobalPos) {
QPoint localPos = m_mainWindow->mapFromGlobal(mouseGlobalPos);
QRect mainFrameGeometry = m_mainWindow->rect();
if (!mainFrameGeometry.contains(localPos)) {
return;
}
if (isMouseOverCurrentToolBarDockingHolder(localPos)) {
return;
}
DockToolBarHolder* holder = resolveToolbarDockingHolder(localPos);
if (holder != m_currentToolBarDockingHolder) {
hideCurrentToolBarDockingHolder();
if (holder) {
holder->open();
}
}
m_currentToolBarDockingHolder = holder;
});
mainWindow()->showPanelDockingHolderRequested().onReceive(this, [this](const QPoint& mouseGlobalPos) {
QPoint localPos = m_mainWindow->mapFromGlobal(mouseGlobalPos);
QRect mainFrameGeometry = m_mainWindow->rect();
if (!mainFrameGeometry.contains(localPos)) {
return;
}
if (isMouseOverCurrentPanelDockingHolder(localPos)) {
return;
}
DockPanelHolder* holder = resolvePanelDockingHolder(localPos);
if (holder != m_currentPanelDockingHolder) {
hideCurrentPanelDockingHolder();
if (holder) {
qDebug() << holder->location();
holder->open();
}
}
m_currentPanelDockingHolder = holder;
});
dockWindowProvider()->init(this);
startupScenario()->run();
}
@ -195,14 +136,48 @@ void DockWindow::loadPage(const QString& uri)
restorePageState(newPage->objectName());
initDocks(newPage);
QStringList allDockNames;
for (DockBase* dock : newPage->allDocks()) {
if (!dock->isVisible()) {
dock->close();
}
allDockNames << dock->objectName();
}
m_currentPageUri = uri;
emit currentPageUriChanged(uri);
m_docksOpenStatusChanged.send(allDockNames);
}
void DockWindow::setToolBarOrientation(const QString& toolBarName, framework::Orientation orientation)
{
const DockPage* page = currentPage();
DockToolBar* toolBar = page ? dynamic_cast<DockToolBar*>(page->dockByName(toolBarName)) : nullptr;
if (toolBar) {
toolBar->setOrientation(static_cast<Qt::Orientation>(orientation));
}
}
void DockWindow::showDockingHolder(const QPoint& globalPos, DockingHolderType type)
{
switch (type) {
case ToolBar:
showToolBarDockingHolder(globalPos);
break;
case Panel:
showPanelDockingHolder(globalPos);
break;
}
}
void DockWindow::hideAllDockingHolders()
{
hideCurrentToolBarDockingHolder();
hideCurrentPanelDockingHolder();
}
bool DockWindow::isDockOpen(const QString& dockName) const
@ -216,6 +191,7 @@ void DockWindow::toggleDock(const QString& dockName)
DockPage* currPage = currentPage();
if (currPage) {
currPage->toggleDock(dockName);
m_docksOpenStatusChanged.send({ dockName });
}
}
@ -224,6 +200,26 @@ void DockWindow::setDockOpen(const QString& dockName, bool open)
DockPage* currPage = currentPage();
if (currPage) {
currPage->setDockOpen(dockName, open);
m_docksOpenStatusChanged.send({ dockName });
}
}
Channel<QStringList> DockWindow::docksOpenStatusChanged() const
{
return m_docksOpenStatusChanged;
}
bool DockWindow::isDockFloating(const QString& dockName) const
{
const DockPage* currPage = currentPage();
return currPage ? currPage->isDockFloating(dockName) : false;
}
void DockWindow::toggleDockFloating(const QString& dockName)
{
DockPage* currPage = currentPage();
if (currPage) {
currPage->toggleDockFloating(dockName);
}
}
@ -420,14 +416,14 @@ void DockWindow::saveGeometry()
/// and restore only the application geometry.
/// Therefore, for correct operation after saving or restoring geometry,
/// it is necessary to apply the appropriate method for the state.
configuration()->setWindowGeometry(windowState());
uiConfiguration()->setWindowGeometry(windowState());
}
void DockWindow::restoreGeometry()
{
TRACEFUNC;
if (!restoreLayout(configuration()->windowGeometry())) {
if (!restoreLayout(uiConfiguration()->windowGeometry())) {
LOGE() << "Could not restore the window geometry!";
}
}
@ -436,7 +432,7 @@ void DockWindow::savePageState(const QString& pageName)
{
TRACEFUNC;
configuration()->setPageState(pageName, windowState());
uiConfiguration()->setPageState(pageName, windowState());
}
void DockWindow::restorePageState(const QString& pageName)
@ -444,7 +440,7 @@ void DockWindow::restorePageState(const QString& pageName)
TRACEFUNC;
/// NOTE: Do not restore geometry
bool ok = restoreLayout(configuration()->pageState(pageName), KDDockWidgets::RestoreOption::RestoreOption_RelativeToMainWindow);
bool ok = restoreLayout(uiConfiguration()->pageState(pageName), KDDockWidgets::RestoreOption::RestoreOption_RelativeToMainWindow);
if (!ok) {
LOGE() << "Could not restore the state of " << pageName << "!";
}
@ -566,6 +562,32 @@ DockPanelHolder* DockWindow::resolvePanelDockingHolder(const QPoint& localPos) c
return newHolder;
}
void DockWindow::showToolBarDockingHolder(const QPoint& globalPos)
{
QPoint localPos = m_mainWindow->mapFromGlobal(globalPos);
QRect mainFrameGeometry = m_mainWindow->rect();
if (!mainFrameGeometry.contains(localPos)) {
return;
}
if (isMouseOverCurrentToolBarDockingHolder(localPos)) {
return;
}
DockToolBarHolder* holder = resolveToolbarDockingHolder(localPos);
if (holder != m_currentToolBarDockingHolder) {
hideCurrentToolBarDockingHolder();
if (holder) {
holder->open();
}
}
m_currentToolBarDockingHolder = holder;
}
void DockWindow::hideCurrentToolBarDockingHolder()
{
if (!m_currentToolBarDockingHolder) {
@ -576,6 +598,33 @@ void DockWindow::hideCurrentToolBarDockingHolder()
m_currentToolBarDockingHolder = nullptr;
}
void DockWindow::showPanelDockingHolder(const QPoint& globalPos)
{
QPoint localPos = m_mainWindow->mapFromGlobal(globalPos);
QRect mainFrameGeometry = m_mainWindow->rect();
if (!mainFrameGeometry.contains(localPos)) {
return;
}
if (isMouseOverCurrentPanelDockingHolder(localPos)) {
return;
}
DockPanelHolder* holder = resolvePanelDockingHolder(localPos);
if (holder != m_currentPanelDockingHolder) {
hideCurrentPanelDockingHolder();
if (holder) {
qDebug() << holder->location();
holder->open();
}
}
m_currentPanelDockingHolder = holder;
}
void DockWindow::hideCurrentPanelDockingHolder()
{
if (!m_currentPanelDockingHolder) {

View file

@ -32,9 +32,10 @@
#include "modularity/ioc.h"
#include "async/asyncable.h"
#include "ui/iuiconfiguration.h"
#include "ui/imainwindow.h"
#include "async/asyncable.h"
#include "internal/istartupscenario.h"
#include "idockwindow.h"
#include "idockwindowprovider.h"
namespace KDDockWidgets {
class MainWindowBase;
@ -47,7 +48,7 @@ class DockToolBarHolder;
class DockPanelHolder;
class DockPage;
class DockBase;
class DockWindow : public QQuickItem, public async::Asyncable
class DockWindow : public QQuickItem, public IDockWindow, public async::Asyncable
{
Q_OBJECT
@ -59,12 +60,13 @@ class DockWindow : public QQuickItem, public async::Asyncable
* mainToolBarDockingHolder READ mainToolBarDockingHolder WRITE setMainToolBarDockingHolder NOTIFY mainToolBarDockingHolderChanged)
Q_PROPERTY(QQmlListProperty<mu::dock::DockPage> pages READ pagesProperty)
INJECT(dock, ui::IUiConfiguration, configuration)
INJECT(dock, ui::IMainWindow, mainWindow)
INJECT(dock, IDockWindowProvider, dockWindowProvider)
INJECT(dock, ui::IUiConfiguration, uiConfiguration)
INJECT(dock, appshell::IStartupScenario, startupScenario)
public:
explicit DockWindow(QQuickItem* parent = nullptr);
~DockWindow() override;
QString currentPageUri() const;
@ -74,9 +76,19 @@ public:
Q_INVOKABLE void loadPage(const QString& uri);
bool isDockOpen(const QString& dockName) const;
void toggleDock(const QString& dockName);
void setDockOpen(const QString& dockName, bool open);
//! IDockWindow
void setToolBarOrientation(const QString& toolBarName, framework::Orientation orientation) override;
void showDockingHolder(const QPoint& globalPos, DockingHolderType type) override;
void hideAllDockingHolders() override;
bool isDockOpen(const QString& dockName) const override;
void toggleDock(const QString& dockName) override;
void setDockOpen(const QString& dockName, bool open) override;
async::Channel<QStringList> docksOpenStatusChanged() const override;
bool isDockFloating(const QString& dockName) const override;
void toggleDockFloating(const QString& dockName) override;
public slots:
void setMainToolBarDockingHolder(DockToolBarHolder* mainToolBarDockingHolder);
@ -116,10 +128,12 @@ private:
void initDocks(DockPage* page);
DockToolBarHolder* resolveToolbarDockingHolder(const QPoint& localPos) const;
void showToolBarDockingHolder(const QPoint& globalPos);
void hideCurrentToolBarDockingHolder();
bool isMouseOverCurrentToolBarDockingHolder(const QPoint& mouseLocalPos) const;
DockPanelHolder* resolvePanelDockingHolder(const QPoint& localPos) const;
void showPanelDockingHolder(const QPoint& globalPos);
void hideCurrentPanelDockingHolder();
bool isMouseOverCurrentPanelDockingHolder(const QPoint& mouseLocalPos) const;
@ -130,6 +144,7 @@ private:
uicomponents::QmlListProperty<DockPage> m_pages;
DockToolBarHolder* m_currentToolBarDockingHolder = nullptr;
DockPanelHolder* m_currentPanelDockingHolder = nullptr;
async::Channel<QStringList> m_docksOpenStatusChanged;
bool m_quiting = false;
};

View file

@ -0,0 +1,58 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*/
#ifndef MU_DOCK_IDOCKWINDOW_H
#define MU_DOCK_IDOCKWINDOW_H
#include "globaltypes.h"
#include "async/channel.h"
#include <QString>
class QPoint;
namespace mu::dock {
class IDockWindow
{
public:
virtual ~IDockWindow() = default;
enum DockingHolderType {
Panel,
ToolBar
};
virtual void setToolBarOrientation(const QString& toolBarName, framework::Orientation orientation) = 0;
virtual void showDockingHolder(const QPoint& globalPos, DockingHolderType type) = 0;
virtual void hideAllDockingHolders() = 0;
virtual bool isDockOpen(const QString& dockName) const = 0;
virtual void setDockOpen(const QString& dockName, bool open) = 0;
virtual void toggleDock(const QString& dockName) = 0;
virtual async::Channel<QStringList> docksOpenStatusChanged() const = 0;
virtual bool isDockFloating(const QString& dockName) const = 0;
virtual void toggleDockFloating(const QString& dockName) = 0;
};
}
#endif // MU_DOCK_IDOCKWINDOW_H

View file

@ -19,25 +19,27 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_APPSHELL_INOTATIONPAGESTATE_H
#define MU_APPSHELL_INOTATIONPAGESTATE_H
#ifndef MU_DOCK_IDOCKWINDOWPROVIDER_H
#define MU_DOCK_IDOCKWINDOWPROVIDER_H
#include "modularity/imoduleexport.h"
#include "appshelltypes.h"
#include "async/channel.h"
#include "async/notification.h"
namespace mu::appshell {
class INotationPageState : MODULE_EXPORT_INTERFACE
namespace mu::dock {
class IDockWindow;
class IDockWindowProvider : MODULE_EXPORT_INTERFACE
{
INTERFACE_ID(INotationPageState)
INTERFACE_ID(IDockWindowProvider)
public:
virtual ~INotationPageState() = default;
virtual ~IDockWindowProvider() = default;
virtual bool isPanelVisible(PanelType type) const = 0;
virtual void setIsPanelsVisible(const std::map<PanelType, bool>& panelsVisible) = 0;
virtual async::Channel<PanelTypeList> panelsVisibleChanged() const = 0;
virtual void init(IDockWindow* window) = 0;
virtual void deinit() = 0;
virtual IDockWindow* window() const = 0;
virtual async::Notification windowChanged() const = 0;
};
}
#endif // MU_APPSHELL_NOTATIONPAGESTATE_H
#endif // MU_DOCK_IDOCKWINDOWPROVIDER_H

View file

@ -170,8 +170,8 @@ void DockBase::setFloating(bool floating)
return;
}
m_floating = floating;
emit floatingChanged();
m_dockWidget->setFloating(floating);
doSetFloating(floating);
}
void DockBase::setLocation(DockLocation location)
@ -312,7 +312,13 @@ void DockBase::listenFloatingChanges()
}
connect(frame, &KDDockWidgets::Frame::isInMainWindowChanged, this, [=]() {
setFloating(!frame->isInMainWindow());
doSetFloating(!frame->isInMainWindow());
}, Qt::UniqueConnection);
});
}
void DockBase::doSetFloating(bool floating)
{
m_floating = floating;
emit floatingChanged();
}

View file

@ -121,6 +121,8 @@ private:
void applySizeConstraints();
void listenFloatingChanges();
void doSetFloating(bool floating);
int m_minimumWidth = 0;
int m_minimumHeight = 0;
int m_maximumWidth = 0;

View file

@ -32,8 +32,11 @@
#include "log.h"
#include "ui/view/abstractmenumodel.h"
using namespace mu::dock;
using namespace mu::actions;
using namespace mu::ui;
DockFrameModel::DockFrameModel(QObject* parent)
: QObject(parent)
@ -76,7 +79,7 @@ QVariantList DockFrameModel::tabs() const
for (const KDDockWidgets::DockWidgetBase* dock : frame->dockWidgets()) {
QVariantMap tab;
tab["title"] = dock->title();
tab[CONTEXT_MENU_MODEL_PROPERTY] = dock->property(CONTEXT_MENU_MODEL_PROPERTY).value<QVariant>();
tab[CONTEXT_MENU_MODEL_PROPERTY] = dock->property(CONTEXT_MENU_MODEL_PROPERTY);
result << tab;
}
@ -179,7 +182,7 @@ QString DockFrameModel::currentDockUniqueName() const
QVariant DockFrameModel::currentDockContextMenuModel() const
{
return currentDockProperty(CONTEXT_MENU_MODEL_PROPERTY).value<QVariant>();
return currentDockProperty(CONTEXT_MENU_MODEL_PROPERTY);
}
const QObject* DockFrameModel::currentDockObject() const
@ -194,11 +197,11 @@ QVariant DockFrameModel::currentDockProperty(const char* propertyName) const
return obj ? obj->property(propertyName) : QVariant();
}
void DockFrameModel::handleMenuItem(const QVariant& item)
void DockFrameModel::handleMenuItem(const QString& itemId) const
{
ActionCode code = codeFromQString(item.toMap()["code"].toString());
auto menuModel = currentDockContextMenuModel().value<AbstractMenuModel*>();
if (!code.empty()) {
dispatcher()->dispatch(code);
if (menuModel) {
menuModel->handleMenuItem(itemId);
}
}

View file

@ -54,7 +54,7 @@ public:
QString currentDockUniqueName() const;
QVariant currentDockContextMenuModel() const;
Q_INVOKABLE void handleMenuItem(const QVariant& item);
Q_INVOKABLE void handleMenuItem(const QString& itemId) const;
public slots:
void setFrame(QQuickItem* item);

View file

@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*/
#include "dockwindowactionscontroller.h"
using namespace mu::dock;
using namespace mu::actions;
static QString dockNameFromArgs(const ActionData& args)
{
return args.count() > 0 ? args.arg<QString>(0) : QString();
}
void DockWindowActionsController::init()
{
dispatcher()->reg(this, "set-dock-open", this, &DockWindowActionsController::setDockOpen);
dispatcher()->reg(this, "toggle-dock", this, &DockWindowActionsController::toggleOpened);
dispatcher()->reg(this, "toggle-floating", this, &DockWindowActionsController::toggleFloating);
}
void DockWindowActionsController::setDockOpen(const ActionData& args)
{
if (args.count() < 2) {
return;
}
QString dockName = args.arg<QString>(0);
bool open = args.arg<bool>(1);
window()->setDockOpen(dockName, open);
}
void DockWindowActionsController::toggleOpened(const ActionData& args)
{
QString dockName = dockNameFromArgs(args);
window()->toggleDock(dockName);
}
void DockWindowActionsController::toggleFloating(const ActionData& args)
{
QString dockName = dockNameFromArgs(args);
window()->toggleDockFloating(dockName);
}
IDockWindow* DockWindowActionsController::window() const
{
return dockWindowProvider()->window();
}

View file

@ -19,32 +19,32 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MU_APPSHELL_NOTATIONPAGESTATE_H
#define MU_APPSHELL_NOTATIONPAGESTATE_H
#ifndef MU_DOCK_DOCKWINDOWACTIONSCONTROLLER_H
#define MU_DOCK_DOCKWINDOWACTIONSCONTROLLER_H
#include "actions/actionable.h"
#include "modularity/ioc.h"
#include "async/asyncable.h"
#include "inotationpagestate.h"
#include "iappshellconfiguration.h"
#include "actions/iactionsdispatcher.h"
#include "../idockwindowprovider.h"
namespace mu::appshell {
class NotationPageState : public INotationPageState, public async::Asyncable
namespace mu::dock {
class DockWindowActionsController : public actions::Actionable
{
INJECT(appshell, IAppShellConfiguration, configuration)
INJECT(dock, IDockWindowProvider, dockWindowProvider)
INJECT(dock, actions::IActionsDispatcher, dispatcher)
public:
void init();
bool isPanelVisible(PanelType type) const override;
void setIsPanelsVisible(const std::map<PanelType, bool>& panelsVisible) override;
mu::async::Channel<PanelTypeList> panelsVisibleChanged() const override;
private:
void setIsPanelVisible(PanelType type, bool visible);
void setDockOpen(const actions::ActionData& args);
void toggleOpened(const actions::ActionData& args);
void toggleFloating(const actions::ActionData& args);
mutable std::map<PanelType, bool> m_panelVisibleMap;
async::Channel<PanelTypeList> m_panelsVisibleChanged;
IDockWindow* window() const;
};
}
#endif // MU_APPSHELL_NOTATIONPAGESTATE_H
#endif // MU_DOCK_DOCKWINDOWACTIONSCONTROLLER_H

View file

@ -0,0 +1,58 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*/
#include "dockwindowprovider.h"
#include "log.h"
using namespace mu::dock;
using namespace mu::async;
void DockWindowProvider::init(IDockWindow* window)
{
IF_ASSERT_FAILED_X(m_window == nullptr, "Window for this DockWindowProvider is already set. Refusing to set it again") {
return;
}
setWindow(window);
}
void DockWindowProvider::deinit()
{
setWindow(nullptr);
}
void DockWindowProvider::setWindow(IDockWindow* window)
{
m_window = window;
m_windowChanged.notify();
}
IDockWindow* DockWindowProvider::window() const
{
return m_window;
}
Notification DockWindowProvider::windowChanged() const
{
return m_windowChanged;
}

View file

@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
*/
#ifndef MU_DOCK_DOCKWINDOWPROVIDER_H
#define MU_DOCK_DOCKWINDOWPROVIDER_H
#include "../idockwindowprovider.h"
namespace mu::dock {
class DockWindowProvider : public IDockWindowProvider
{
public:
void init(IDockWindow* window) override;
void deinit() override;
IDockWindow* window() const override;
async::Notification windowChanged() const override;
private:
void setWindow(IDockWindow* window);
IDockWindow* m_window = nullptr;
async::Notification m_windowChanged;
};
}
#endif // MU_DOCK_DOCKWINDOWPROVIDER_H

View file

@ -23,6 +23,8 @@
#include "dropindicators.h"
#include "dropindicatorswindow.h"
#include "../idockwindow.h"
#include "thirdparty/KDDockWidgets/src/Config.h"
#include "thirdparty/KDDockWidgets/src/private/DragController_p.h"
#include "thirdparty/KDDockWidgets/src/private/Utils_p.h"
@ -105,11 +107,11 @@ KDDockWidgets::DropIndicatorOverlayInterface::DropLocation DropIndicators::hover
}
if (needShowToolBarHolders()) {
mainWindow()->requestShowToolBarDockingHolder(globalPos);
dockWindow()->showDockingHolder(globalPos, IDockWindow::ToolBar);
}
if (needShowPanelHolders()) {
mainWindow()->requestShowPanelDockingHolder(globalPos);
dockWindow()->showDockingHolder(globalPos, IDockWindow::Panel);
}
if (isDropAllowed(dropLocation)) {
@ -197,7 +199,7 @@ void DropIndicators::updateVisibility()
updateWindowPosition();
m_indicatorsWindow->raise();
} else {
mainWindow()->requestHideAllDockingHolders();
dockWindow()->hideAllDockingHolders();
hideDropArea();
}
@ -470,7 +472,7 @@ void DropIndicators::updateToolBarOrientation()
newOrientation = framework::Orientation::Vertical;
}
mainWindow()->requestChangeToolBarOrientation(draggedDock->uniqueName(), newOrientation);
dockWindow()->setToolBarOrientation(draggedDock->uniqueName(), newOrientation);
}
void DropIndicators::updateWindowPosition()
@ -483,3 +485,8 @@ void DropIndicators::updateWindowPosition()
}
m_indicatorsWindow->setGeometry(rect);
}
IDockWindow* DropIndicators::dockWindow() const
{
return dockWindowProvider()->window();
}

View file

@ -25,10 +25,8 @@
#include "modularity/ioc.h"
#include "../docktypes.h"
#include "ui/imainwindow.h"
#include "modularity/ioc.h"
#include "ui/imainwindow.h"
#include "../idockwindowprovider.h"
#include "globaltypes.h"
#include "thirdparty/KDDockWidgets/src/private/DropIndicatorOverlayInterface_p.h"
@ -50,7 +48,7 @@ class DropIndicators : public KDDockWidgets::DropIndicatorOverlayInterface
Q_PROPERTY(bool innerTopIndicatorVisible READ innerTopIndicatorVisible NOTIFY indicatorsVisibilityChanged)
Q_PROPERTY(bool innerBottomIndicatorVisible READ innerBottomIndicatorVisible NOTIFY indicatorsVisibilityChanged)
INJECT(dock, ui::IMainWindow, mainWindow)
INJECT(dock, IDockWindowProvider, dockWindowProvider)
public:
explicit DropIndicators(KDDockWidgets::DropArea* dropArea);
@ -102,6 +100,8 @@ private:
void updateWindowPosition();
IDockWindow* dockWindow() const;
KDDockWidgets::QWidgetOrQuick* m_rubberBand = nullptr;
DropIndicatorsWindow* m_indicatorsWindow = nullptr;
};

View file

@ -23,10 +23,11 @@
#include "log.h"
#include "dockwindow/dockwindow.h"
#include "internal/applicationuiactions.h"
using namespace mu::appshell;
using namespace mu::notation;
using namespace mu::actions;
NotationPageModel::NotationPageModel(QObject* parent)
: QObject(parent)
@ -35,147 +36,106 @@ NotationPageModel::NotationPageModel(QObject* parent)
bool NotationPageModel::isNavigatorVisible() const
{
return pageState()->isPanelVisible(PanelType::NotationNavigator);
return configuration()->isNotationNavigatorVisible();
}
void NotationPageModel::setNoteInputBarDockName(const QString& dockName)
void NotationPageModel::init()
{
setPanelDockName(PanelType::NoteInputBar, dockName);
}
TRACEFUNC;
void NotationPageModel::setNotationToolBarDockName(const QString& dockName)
{
setPanelDockName(PanelType::NotationToolBar, dockName);
}
void NotationPageModel::setPlaybackToolBarDockName(const QString& dockName)
{
setPanelDockName(PanelType::PlaybackToolBar, dockName);
}
void NotationPageModel::setUndoRedoToolBarDockName(const QString& dockName)
{
setPanelDockName(PanelType::UndoRedoToolBar, dockName);
}
void NotationPageModel::setPalettesPanelDockName(const QString& dockName)
{
setPanelDockName(PanelType::Palettes, dockName);
}
void NotationPageModel::setInstrumentsPanelDockName(const QString& dockName)
{
setPanelDockName(PanelType::Instruments, dockName);
}
void NotationPageModel::setInspectorPanelDockName(const QString& dockName)
{
setPanelDockName(PanelType::Inspector, dockName);
}
void NotationPageModel::setSelectionFilterPanelDockName(const QString& dockName)
{
setPanelDockName(PanelType::SelectionFilter, dockName);
}
void NotationPageModel::setPianoRollDockName(const QString& dockName)
{
setPanelDockName(PanelType::Piano, dockName);
}
void NotationPageModel::setMixerDockName(const QString& dockName)
{
setPanelDockName(PanelType::Mixer, dockName);
}
void NotationPageModel::setTimelineDockName(const QString& dockName)
{
setPanelDockName(PanelType::Timeline, dockName);
}
void NotationPageModel::setDrumsetPanelDockName(const QString& dockName)
{
setPanelDockName(PanelType::DrumsetPanel, dockName);
}
void NotationPageModel::setStatusBarDockName(const QString& dockName)
{
setPanelDockName(PanelType::NotationStatusBar, dockName);
}
void NotationPageModel::setPanelDockName(PanelType type, const QString& dockName)
{
m_panelTypeToDockName[type] = dockName;
}
void NotationPageModel::init(QQuickItem* dockWindow)
{
m_window = dynamic_cast<dock::DockWindow*>(dockWindow);
IF_ASSERT_FAILED(m_window) {
return;
for (const ActionCode& actionCode : ApplicationUiActions::toggleDockActions().keys()) {
DockName dockName = ApplicationUiActions::toggleDockActions()[actionCode];
dispatcher()->reg(this, actionCode, [=]() { toggleDock(dockName); });
}
IF_ASSERT_FAILED(!m_panelTypeToDockName.isEmpty()) {
return;
}
std::map<PanelType, bool> initialState;
for (PanelType type : m_panelTypeToDockName.keys()) {
initialState[type] = m_window->isDockOpen(m_panelTypeToDockName[type]);
}
pageState()->setIsPanelsVisible(initialState);
static const QMap<std::string, PanelType> actionToPanelType {
{ "toggle-navigator", PanelType::NotationNavigator },
{ "toggle-mixer", PanelType::Mixer },
{ "toggle-timeline", PanelType::Timeline },
{ "toggle-palettes", PanelType::Palettes },
{ "toggle-instruments", PanelType::Instruments },
{ "inspector", PanelType::Inspector },
{ "toggle-selection-filter", PanelType::SelectionFilter },
{ "toggle-statusbar", PanelType::NotationStatusBar },
{ "toggle-noteinput", PanelType::NoteInputBar },
{ "toggle-notationtoolbar", PanelType::NotationToolBar },
{ "toggle-undoredo", PanelType::UndoRedoToolBar },
{ "toggle-transport", PanelType::PlaybackToolBar }
};
for (const std::string& actionCode : actionToPanelType.keys()) {
dispatcher()->reg(this, actionCode, [=]() { togglePanel(actionToPanelType[actionCode]); });
}
pageState()->panelsVisibleChanged().onReceive(this, [this](PanelTypeList types) {
for (PanelType type : types) {
if (type == PanelType::NotationNavigator) {
emit isNavigatorVisibleChanged();
}
}
});
updateDrumsetPanelVisibility();
globalContext()->currentNotationChanged().onNotify(this, [=]() {
updateDrumsetPanelVisibility();
});
}
void NotationPageModel::togglePanel(PanelType type)
QString NotationPageModel::notationToolBarName() const
{
IF_ASSERT_FAILED(m_window) {
return NOTATION_TOOLBAR_NAME;
}
QString NotationPageModel::playbackToolBarName() const
{
return PLAYBACK_TOOLBAR_NAME;
}
QString NotationPageModel::undoRedoToolBarName() const
{
return UNDO_REDO_TOOLBAR_NAME;
}
QString NotationPageModel::noteInputBarName() const
{
return NOTE_INPUT_BAR_NAME;
}
QString NotationPageModel::palettesPanelName() const
{
return PALETTES_PANEL_NAME;
}
QString NotationPageModel::instrumentsPanelName() const
{
return INSTRUMENTS_PANEL_NAME;
}
QString NotationPageModel::inspectorPanelName() const
{
return INSPECTOR_PANEL_NAME;
}
QString NotationPageModel::selectionFiltersPanelName() const
{
return SELECTION_FILTERS_PANEL_NAME;
}
QString NotationPageModel::pianoPanelName() const
{
return PIANO_PANEL_NAME;
}
QString NotationPageModel::mixerPanelName() const
{
return MIXER_PANEL_NAME;
}
QString NotationPageModel::timelinePanelName() const
{
return TIMELINE_PANEL_NAME;
}
QString NotationPageModel::drumsetPanelName() const
{
return DRUMSET_PANEL_NAME;
}
QString NotationPageModel::statusBarName() const
{
return NOTATION_STATUSBAR_NAME;
}
void NotationPageModel::toggleDock(const QString& name)
{
if (name == NOTATION_NAVIGATOR_PANEL_NAME) {
configuration()->setIsNotationNavigatorVisible(!isNavigatorVisible());
emit isNavigatorVisibleChanged();
return;
}
bool visible = pageState()->isPanelVisible(type);
pageState()->setIsPanelsVisible({ { type, !visible } });
m_window->toggleDock(m_panelTypeToDockName[type]);
dispatcher()->dispatch("toggle-dock", ActionData::make_arg1<QString>(name));
}
void NotationPageModel::updateDrumsetPanelVisibility()
{
TRACEFUNC;
auto setDrumsetPanelVisible = [this](bool visible) {
m_window->setDockOpen(m_panelTypeToDockName[PanelType::DrumsetPanel], visible);
pageState()->setIsPanelsVisible({ { PanelType::DrumsetPanel, visible } });
dispatcher()->dispatch("set-dock-open", ActionData::make_arg2<QString, bool>(DRUMSET_PANEL_NAME, visible));
};
setDrumsetPanelVisible(false);

View file

@ -29,20 +29,16 @@
#include "actions/actionable.h"
#include "actions/iactionsdispatcher.h"
#include "context/iglobalcontext.h"
#include "inotationpagestate.h"
namespace mu::dock {
class DockWindow;
}
#include "iappshellconfiguration.h"
namespace mu::appshell {
class NotationPageModel : public QObject, public async::Asyncable, public actions::Actionable
{
Q_OBJECT
INJECT(appshell, INotationPageState, pageState)
INJECT(appshell, actions::IActionsDispatcher, dispatcher)
INJECT(appshell, context::IGlobalContext, globalContext)
INJECT(appshell, IAppShellConfiguration, configuration)
Q_PROPERTY(bool isNavigatorVisible READ isNavigatorVisible NOTIFY isNavigatorVisibleChanged)
@ -51,36 +47,32 @@ public:
bool isNavigatorVisible() const;
Q_INVOKABLE void setNotationToolBarDockName(const QString& dockName);
Q_INVOKABLE void setPlaybackToolBarDockName(const QString& dockName);
Q_INVOKABLE void setUndoRedoToolBarDockName(const QString& dockName);
Q_INVOKABLE void setNoteInputBarDockName(const QString& dockName);
Q_INVOKABLE void init();
Q_INVOKABLE void setPalettesPanelDockName(const QString& dockName);
Q_INVOKABLE void setInstrumentsPanelDockName(const QString& dockName);
Q_INVOKABLE void setInspectorPanelDockName(const QString& dockName);
Q_INVOKABLE void setSelectionFilterPanelDockName(const QString& dockName);
Q_INVOKABLE QString notationToolBarName() const;
Q_INVOKABLE QString playbackToolBarName() const;
Q_INVOKABLE QString undoRedoToolBarName() const;
Q_INVOKABLE QString noteInputBarName() const;
Q_INVOKABLE void setPianoRollDockName(const QString& dockName);
Q_INVOKABLE void setMixerDockName(const QString& dockName);
Q_INVOKABLE void setTimelineDockName(const QString& dockName);
Q_INVOKABLE void setDrumsetPanelDockName(const QString& dockName);
Q_INVOKABLE QString palettesPanelName() const;
Q_INVOKABLE QString instrumentsPanelName() const;
Q_INVOKABLE QString inspectorPanelName() const;
Q_INVOKABLE QString selectionFiltersPanelName() const;
Q_INVOKABLE void setStatusBarDockName(const QString& dockName);
Q_INVOKABLE QString pianoPanelName() const;
Q_INVOKABLE QString mixerPanelName() const;
Q_INVOKABLE QString timelinePanelName() const;
Q_INVOKABLE QString drumsetPanelName() const;
Q_INVOKABLE void init(QQuickItem* dockWindow);
Q_INVOKABLE QString statusBarName() const;
signals:
void isNavigatorVisibleChanged();
private:
void setPanelDockName(PanelType type, const QString& dockName);
void togglePanel(PanelType type);
void toggleDock(const QString& name);
void updateDrumsetPanelVisibility();
QMap<PanelType, QString /* dockName */> m_panelTypeToDockName;
dock::DockWindow* m_window = nullptr;
};
}

View file

@ -28,12 +28,16 @@ if (OS_IS_MAC)
set(PLATFORM_THEME_SRC
${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosplatformtheme.mm
${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosplatformtheme.h
${CMAKE_CURRENT_LIST_DIR}/view/platform/macos/macosmainwindowprovider.mm
${CMAKE_CURRENT_LIST_DIR}/view/platform/macos/macosmainwindowprovider.h
)
# Don't mix C++ and Objective-C++ in Unity Build
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosplatformtheme.mm
${CMAKE_CURRENT_LIST_DIR}/view/platform/macos/macosmainwindowprovider.mm
PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/internal/platform/macos/macosplatformtheme.mm
${CMAKE_CURRENT_LIST_DIR}/view/platform/macos/macosmainwindowprovider.mm
PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
elseif(OS_IS_WIN)
set(PLATFORM_THEME_SRC
@ -116,6 +120,8 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/view/qmlaccessible.h
${CMAKE_CURRENT_LIST_DIR}/view/widgetview.cpp
${CMAKE_CURRENT_LIST_DIR}/view/widgetview.h
${CMAKE_CURRENT_LIST_DIR}/view/mainwindowprovider.cpp
${CMAKE_CURRENT_LIST_DIR}/view/mainwindowprovider.h
${CMAKE_CURRENT_LIST_DIR}/dev/interactivetestsmodel.cpp
${CMAKE_CURRENT_LIST_DIR}/dev/interactivetestsmodel.h

View file

@ -23,15 +23,9 @@
#define MU_UI_IMAINWINDOW_H
#include "modularity/imoduleexport.h"
#include "async/channel.h"
#include "async/notification.h"
#include "globaltypes.h"
class QMainWindow;
class QWindow;
class QScreen;
class QString;
class QPoint;
namespace mu::ui {
class IMainWindow : MODULE_EXPORT_INTERFACE
@ -53,18 +47,6 @@ public:
virtual bool isFullScreen() const = 0;
virtual void toggleFullScreen() = 0;
virtual const QScreen* screen() const = 0;
virtual void requestChangeToolBarOrientation(const QString& toolBarName, framework::Orientation orientation) = 0;
virtual async::Channel<QString, framework::Orientation> changeToolBarOrientationRequested() const = 0;
virtual void requestShowToolBarDockingHolder(const QPoint& globalPos) = 0;
virtual async::Channel<QPoint> showToolBarDockingHolderRequested() const = 0;
virtual void requestShowPanelDockingHolder(const QPoint& globalPos) = 0;
virtual async::Channel<QPoint> showPanelDockingHolderRequested() const = 0;
virtual void requestHideAllDockingHolders() = 0;
virtual async::Notification hideAllDockingHoldersRequested() const = 0;
};
}

View file

@ -34,10 +34,13 @@
#ifdef Q_OS_MAC
#include "internal/platform/macos/macosplatformtheme.h"
#include "view/platform/macos/macosmainwindowprovider.h"
#elif defined(Q_OS_WIN)
#include "internal/platform/windows/windowsplatformtheme.h"
#include "view/mainwindowprovider.h"
#else
#include "internal/platform/stub/stubplatformtheme.h"
#include "view/mainwindowprovider.h"
#endif
#include "view/qmltooltip.h"
@ -129,6 +132,12 @@ void UiModule::registerUiTypes()
qmlRegisterType<AccessibleItem>("MuseScore.Ui", 1, 0, "AccessibleItem");
qmlRegisterUncreatableType<MUAccessible>("MuseScore.Ui", 1, 0, "MUAccessible", "Cannot create a enum type");
#ifdef Q_OS_MAC
qmlRegisterType<MacOSMainWindowProvider>("MuseScore.Ui", 1, 0, "MainWindowProvider");
#else
qmlRegisterType<MainWindowProvider>("MuseScore.Ui", 1, 0, "MainWindowProvider");
#endif
qmlRegisterType<InteractiveTestsModel>("MuseScore.Ui", 1, 0, "InteractiveTestsModel");
qRegisterMetaType<TestDialog>("TestDialog");

View file

@ -139,11 +139,6 @@ const MenuItemList& AbstractMenuModel::items() const
return m_items;
}
MenuItemList& AbstractMenuModel::items()
{
return m_items;
}
void AbstractMenuModel::setItems(const MenuItemList& items)
{
TRACEFUNC;
@ -171,6 +166,11 @@ int AbstractMenuModel::itemIndex(const actions::ActionCode& actionCode) const
return INVALID_ITEM_INDEX;
}
MenuItem& AbstractMenuModel::item(int index)
{
return m_items[index];
}
MenuItem& AbstractMenuModel::findItem(const QString& itemId)
{
return item(m_items, itemId);

View file

@ -38,7 +38,7 @@ class AbstractMenuModel : public QAbstractListModel, public async::Asyncable
INJECT(ui, IUiActionsRegister, uiactionsRegister)
INJECT(ui, actions::IActionsDispatcher, dispatcher)
Q_PROPERTY(int count READ rowCount NOTIFY itemsChanged)
Q_PROPERTY(int length READ rowCount NOTIFY itemsChanged)
Q_PROPERTY(QVariantList items READ itemsProperty NOTIFY itemsChanged)
public:
@ -51,6 +51,7 @@ public:
virtual void load();
QVariantList itemsProperty() const;
const MenuItemList& items() const;
Q_INVOKABLE void handleMenuItem(const QString& itemId);
Q_INVOKABLE QVariantMap get(int index);
@ -76,15 +77,14 @@ protected:
virtual void onActionsStateChanges(const actions::ActionCodeList& codes);
const MenuItemList& items() const;
MenuItemList& items();
void setItems(const MenuItemList& items);
void clear();
static const int INVALID_ITEM_INDEX;
int itemIndex(const actions::ActionCode& actionCode) const;
MenuItem& item(int index);
MenuItem& findItem(const QString& itemId);
MenuItem& findItem(const actions::ActionCode& actionCode);
MenuItem& findMenu(const QString& menuId);

View file

@ -22,13 +22,14 @@
#include "mainwindowprovider.h"
#include <QWindow>
#include "modularity/ioc.h"
#include "log.h"
using namespace mu::dock;
using namespace mu::async;
#include <QWindow>
using namespace mu::ui;
using namespace mu::modularity;
MainWindowProvider::MainWindowProvider(QObject* parent)
: QObject(parent), m_window(nullptr)
@ -76,7 +77,7 @@ void MainWindowProvider::setWindow(QWindow* window)
void MainWindowProvider::init()
{
modularity::ioc()->registerExport<ui::IMainWindow>("dock", this);
ioc()->registerExport<IMainWindow>("ui", this);
}
QString MainWindowProvider::filePath() const
@ -154,43 +155,3 @@ const QScreen* MainWindowProvider::screen() const
{
return m_window ? m_window->screen() : nullptr;
}
void MainWindowProvider::requestChangeToolBarOrientation(const QString& toolBarName, mu::framework::Orientation orientation)
{
m_dockOrientationChanged.send(toolBarName, orientation);
}
Channel<QString, mu::framework::Orientation> MainWindowProvider::changeToolBarOrientationRequested() const
{
return m_dockOrientationChanged;
}
void MainWindowProvider::requestShowToolBarDockingHolder(const QPoint& globalPos)
{
m_showToolBarDockingHolderRequested.send(globalPos);
}
mu::async::Channel<QPoint> MainWindowProvider::showToolBarDockingHolderRequested() const
{
return m_showToolBarDockingHolderRequested;
}
void MainWindowProvider::requestShowPanelDockingHolder(const QPoint& globalPos)
{
m_showPanelDockingHolderRequested.send(globalPos);
}
mu::async::Channel<QPoint> MainWindowProvider::showPanelDockingHolderRequested() const
{
return m_showPanelDockingHolderRequested;
}
void MainWindowProvider::requestHideAllDockingHolders()
{
m_hideAllHoldersRequested.notify();
}
mu::async::Notification MainWindowProvider::hideAllDockingHoldersRequested() const
{
return m_hideAllHoldersRequested;
}

View file

@ -28,8 +28,8 @@
#include <QObject>
#include <QStack>
namespace mu::dock {
class MainWindowProvider : public QObject, public ui::IMainWindow
namespace mu::ui {
class MainWindowProvider : public QObject, public IMainWindow
{
Q_OBJECT
@ -56,18 +56,6 @@ public:
void toggleFullScreen() override;
const QScreen* screen() const override;
void requestChangeToolBarOrientation(const QString& toolBarName, framework::Orientation orientation) override;
async::Channel<QString, framework::Orientation> changeToolBarOrientationRequested() const override;
void requestShowToolBarDockingHolder(const QPoint& globalPos) override;
async::Channel<QPoint> showToolBarDockingHolderRequested() const override;
void requestShowPanelDockingHolder(const QPoint& globalPos) override;
async::Channel<QPoint> showPanelDockingHolderRequested() const override;
void requestHideAllDockingHolders() override;
async::Notification hideAllDockingHoldersRequested() const override;
signals:
void windowChanged();
void filePathChanged();
@ -85,10 +73,6 @@ private slots: // Should only be used from QML
private:
QStack<QWindow*> m_windows;
async::Channel<QString, framework::Orientation> m_dockOrientationChanged;
async::Channel<QPoint> m_showToolBarDockingHolderRequested;
async::Channel<QPoint> m_showPanelDockingHolderRequested;
async::Notification m_hideAllHoldersRequested;
};
}

View file

@ -26,14 +26,14 @@
#include "modularity/ioc.h"
#include "ui/iuiconfiguration.h"
#include "view/dockwindow/mainwindowprovider.h"
#include "ui/view/mainwindowprovider.h"
namespace mu::dock {
namespace mu::ui {
class MacOSMainWindowProvider : public MainWindowProvider, public async::Asyncable
{
Q_OBJECT
INJECT(appshell, ui::IUiConfiguration, uiConfiguration)
INJECT(appshell, IUiConfiguration, uiConfiguration)
public:
explicit MacOSMainWindowProvider(QObject* parent = nullptr);

View file

@ -24,7 +24,7 @@
#include <Cocoa/Cocoa.h>
#include <QWindow>
using namespace mu::dock;
using namespace mu::ui;
static NSWindow* nsWindowForQWindow(QWindow* qWindow)
{

View file

@ -55,7 +55,7 @@ Item {
function modelSections() {
var _sections = []
for (var i = 0; i < root.model.count; i++) {
for (var i = 0; i < root.model.length; i++) {
var element = root.model.get(i)
var section = element[sectionRole]

View file

@ -33,7 +33,7 @@ FlatButton {
property int menuOffsetY: 0
property int menuAlign: 0
signal handleMenuItem(var item)
signal handleMenuItem(string itemId)
function toggleMenu(item, x, y) {
menuLoader.parent = item
@ -51,7 +51,7 @@ FlatButton {
navigation: root.navigation
onHandleMenuItem: {
root.handleMenuItem(item)
root.handleMenuItem(itemId)
}
}

View file

@ -34,7 +34,7 @@ StyledPopupView {
property int preferredAlign: Qt.AlignRight // Left, HCenter, Right
signal handleMenuItem(var item)
signal handleMenuItem(string itemId)
x: {
switch(preferredAlign) {
@ -87,7 +87,7 @@ StyledPopupView {
//! - all selectable items that are selected get an accent color background
for (let i = 0; i < model.length; i++) {
let item = model[i]
let item = prv.getItem(i)
let hasIcon = (Boolean(item.icon) && item.icon !== IconCode.NONE)
if (item.checkable && hasIcon) {
@ -110,7 +110,7 @@ StyledPopupView {
let rightWidth = 0
for (let j = 0; j < model.length; j++) {
prv.testItem.modelData = model[j]
prv.testItem.modelData = prv.getItem(j)
leftWidth = Math.max(leftWidth, prv.testItem.calculatedLeftPartWidth())
rightWidth = Math.max(rightWidth, prv.testItem.calculatedRightPartWidth())
}
@ -124,7 +124,7 @@ StyledPopupView {
// Let's manually adjust the height of the content
var sepCount = 0
for (let k = 0; k < model.length; k++) {
if (!Boolean(model[k].title)) {
if (!Boolean(prv.getItem(k).title)) {
sepCount++
}
}
@ -198,6 +198,14 @@ StyledPopupView {
}
return false
}
function getItem(row) {
if (Boolean(root.model.get)) {
return root.model.get(row)
}
return root.model[row]
}
}
ListView {
@ -213,12 +221,13 @@ StyledPopupView {
delegate: Loader {
id: loader
property bool isSeparator: !Boolean(modelData.title) || modelData.title === ""
property var itemData: Boolean(root.model.get) ? model : modelData
property bool isSeparator: !Boolean(itemData.title) || itemData.title === ""
sourceComponent: isSeparator ? separatorComp : menuItemComp
onLoaded: {
loader.item.modelData = Qt.binding(() => (modelData))
loader.item.modelData = Qt.binding(() => (itemData))
loader.item.width = Qt.binding(() => (prv.itemWidth))
}
@ -265,7 +274,7 @@ StyledPopupView {
// NOTE: reset view state
view.update()
root.handleMenuItem(item)
root.handleMenuItem(itemId)
}
onRequestParentItemActive: {

View file

@ -42,7 +42,7 @@ ListItemBlank {
property int padding: 0
signal handleMenuItem(var item)
signal handleMenuItem(string itemId)
signal openSubMenuRequested(var menu)
signal subMenuShowed(var menu)
@ -150,8 +150,8 @@ ListItemBlank {
menu.model = modelData.subitems
menu.handleMenuItem.connect(function(item) {
Qt.callLater(root.handleMenuItem, item)
menu.handleMenuItem.connect(function(itemId) {
Qt.callLater(root.handleMenuItem, itemId)
menu.close()
})
@ -311,6 +311,6 @@ ListItemBlank {
return
}
root.handleMenuItem(modelData)
root.handleMenuItem(modelData.id)
}
}

View file

@ -24,7 +24,7 @@ import QtQuick 2.15
Loader {
id: loader
signal handleMenuItem(var item)
signal handleMenuItem(string itemId)
property alias menu: loader.item
property var menuAnchorItem: null
@ -52,7 +52,7 @@ Loader {
onHandleMenuItem: {
itemMenu.close()
Qt.callLater(loader.handleMenuItem, item)
Qt.callLater(loader.handleMenuItem, itemId)
}
onClosed: {
@ -118,6 +118,7 @@ Loader {
menu.y = y
}
}
Timer {
id: focusOnOpenedMenuTimer

View file

@ -85,8 +85,8 @@ Column {
menuAlign: Qt.AlignHCenter
onHandleMenuItem: function(item) {
switch (item.id) {
onHandleMenuItem: function(itemId) {
switch (itemId) {
case "reset":
root.propertyItem.resetToDefault()
break

View file

@ -36,8 +36,7 @@ Item {
id: root
property NavigationSection navigationSection: null
signal contextMenuModelChanged(var newModel)
property alias contextMenuModel: contextMenuModel
Rectangle {
id: background
@ -66,10 +65,6 @@ Item {
InstrumentsPanelContextMenuModel {
id: contextMenuModel
onItemsChanged: {
root.contextMenuModelChanged(contextMenuModel.items)
}
}
Component.onCompleted: {

View file

@ -35,6 +35,8 @@ using namespace mu::notation;
using namespace mu::ui;
using namespace mu::actions;
const ActionCode SET_INSTRUMENTS_ORDER_CODE("set-instruments-order");
InstrumentsPanelContextMenuModel::InstrumentsPanelContextMenuModel(QObject* parent)
: AbstractMenuModel(parent)
{
@ -42,6 +44,8 @@ InstrumentsPanelContextMenuModel::InstrumentsPanelContextMenuModel(QObject* pare
void InstrumentsPanelContextMenuModel::load()
{
dispatcher()->reg(this, SET_INSTRUMENTS_ORDER_CODE, this, &InstrumentsPanelContextMenuModel::setInstrumentsOrder);
globalContext()->currentNotationChanged().onNotify(this, [this]() {
INotationPtr notation = globalContext()->currentNotation();
m_masterNotation = globalContext()->currentMasterNotation();
@ -69,31 +73,26 @@ void InstrumentsPanelContextMenuModel::loadItems()
TRACEFUNC;
ScoreOrder currentOrder = m_masterNotation->parts()->scoreOrder();
ScoreOrderList allOrders = instrumentsRepository()->orders();
m_orders = instrumentsRepository()->orders();
if (!allOrders.contains(currentOrder)) {
allOrders.append(currentOrder);
if (!m_orders.contains(currentOrder)) {
m_orders.append(currentOrder);
}
MenuItemList orderItems;
dispatcher()->unReg(this);
for (const ScoreOrder& order : allOrders) {
for (const ScoreOrder& order : m_orders) {
MenuItem orderItem;
orderItem.id = order.id;
orderItem.title = order.name;
orderItem.code = codeFromQString("set-order-" + order.id);
orderItem.code = SET_INSTRUMENTS_ORDER_CODE;
orderItem.checkable = Checkable::Yes;
orderItem.state.enabled = true;
orderItem.state.checked = currentOrder.id == order.id;
orderItem.args = ActionData::make_arg1<QString>(order.id);
orderItems << orderItem;
dispatcher()->reg(this, orderItem.code, [this, order]() {
m_masterNotation->parts()->setScoreOrder(order);
});
}
MenuItemList items {
@ -102,3 +101,19 @@ void InstrumentsPanelContextMenuModel::loadItems()
setItems(items);
}
void InstrumentsPanelContextMenuModel::setInstrumentsOrder(const actions::ActionData& args)
{
if (args.count() <= 0) {
return;
}
QString orderId = args.arg<QString>(0);
for (const ScoreOrder& order : m_orders) {
if (order.id == orderId) {
m_masterNotation->parts()->setScoreOrder(order);
return;
}
}
}

View file

@ -46,8 +46,10 @@ public:
private:
void loadItems();
void setInstrumentsOrder(const actions::ActionData& args);
notation::IMasterNotationPtr m_masterNotation;
notation::ScoreOrderList m_orders;
};
}

View file

@ -44,9 +44,6 @@ class NotationActionController : public actions::Actionable, public async::Async
INJECT(notation, playback::IPlaybackConfiguration, playbackConfiguration)
INJECT(notation, INotationConfiguration, configuration)
private:
std::map<mu::actions::ActionCode, bool (NotationActionController::*)() const> m_isEnabledMap;
public:
void init();
@ -224,6 +221,7 @@ private:
void registerMoveAction(const mu::actions::ActionCode&);
async::Notification m_currentNotationNoteInputChanged;
std::map<mu::actions::ActionCode, bool (NotationActionController::*)() const> m_isEnabledMap;
};
}

View file

@ -196,8 +196,8 @@ FocusScope {
navigation: fakeNavCtrl
onHandleMenuItem: function (item) {
contextMenuModel.handleMenuItem(item.id)
onHandleMenuItem: function (itemId) {
contextMenuModel.handleMenuItem(itemId)
}
}
}

View file

@ -117,7 +117,7 @@ Rectangle {
}
function handleMenuItem() {
Qt.callLater(noteInputModel.handleMenuItem, item.id)
Qt.callLater(noteInputModel.handleMenuItem, itemId)
}
onClicked: function (mouse) {
@ -173,8 +173,8 @@ Rectangle {
navigation: btn.navigation
onHandleMenuItem: function(item) {
noteInputModel.handleMenuItem(item.id)
onHandleMenuItem: function(itemId) {
noteInputModel.handleMenuItem(itemId)
}
}
}

View file

@ -74,7 +74,7 @@ FlatButton {
navigation: root.navigation
onHandleMenuItem: {
Qt.callLater(root.changeCurrentViewModeRequested, item.id)
Qt.callLater(root.changeCurrentViewModeRequested, itemId)
}
}
}

View file

@ -125,7 +125,7 @@ RowLayout {
navigation: menuButton.navigation
onHandleMenuItem: {
root.changeZoomRequested(item.id)
root.changeZoomRequested(itemId)
}
}

View file

@ -134,7 +134,7 @@ ListItemBlank {
]
onHandleMenuItem: {
switch(item.id) {
switch(itemId) {
case "duplicate":
root.copyPartRequested()
break

View file

@ -186,7 +186,8 @@ void NoteInputBarModel::updateState()
{
bool enabled = notation() && !playbackController()->isPlaying();
for (MenuItem& item : items()) {
for (int i = 0; i < rowCount(); ++i) {
MenuItem& item = this->item(i);
item.state.enabled = enabled;
item.state.checked = false;
}
@ -221,8 +222,7 @@ void NoteInputBarModel::updateNoteInputModeState()
return;
}
MenuItemList& items = this->items();
MenuItem& item = items[noteInputModeIndex];
MenuItem& item = this->item(noteInputModeIndex);
QString currentSection = item.section;
MenuItemList subitems = noteInputMethodItems();
@ -234,7 +234,7 @@ void NoteInputBarModel::updateNoteInputModeState()
void NoteInputBarModel::updateNoteDotState()
{
static ActionCodeList dotActions = {
static const ActionCodeList dotActions = {
"pad-dot",
"pad-dotdot",
"pad-dot3",
@ -250,7 +250,7 @@ void NoteInputBarModel::updateNoteDotState()
void NoteInputBarModel::updateNoteDurationState()
{
static ActionCodeList noteActions = {
static const ActionCodeList noteActions = {
"note-longa",
"note-breve",
"pad-note-1",
@ -274,7 +274,7 @@ void NoteInputBarModel::updateNoteDurationState()
void NoteInputBarModel::updateNoteAccidentalState()
{
static ActionCodeList accidentalActions = {
static const ActionCodeList accidentalActions = {
"flat2",
"flat",
"nat",
@ -315,7 +315,7 @@ void NoteInputBarModel::updateSlurState()
void NoteInputBarModel::updateVoicesState()
{
static ActionCodeList voiceActions {
static const ActionCodeList voiceActions {
"voice-1",
"voice-2",
"voice-3",
@ -331,7 +331,7 @@ void NoteInputBarModel::updateVoicesState()
void NoteInputBarModel::updateArticulationsState()
{
static ActionCodeList articulationActions {
static const ActionCodeList articulationActions {
"add-marcato",
"add-sforzato",
"add-tenuto",

View file

@ -631,7 +631,7 @@ GridView {
]
onHandleMenuItem: {
switch(item.id) {
switch(itemId) {
case "delete":
paletteView.paletteController.remove(contextMenu.modelIndex)
break

View file

@ -155,7 +155,7 @@ Item {
]
onHandleMenuItem: {
switch(item.id) {
switch(itemId) {
case "hide": root.hidePaletteRequested(); break
case "new": root.insertNewPaletteRequested(); break
case "edit": root.enableEditingToggled(!root.editingEnabled); break

View file

@ -130,7 +130,9 @@ Rectangle {
navigation: btn.navigation
onHandleMenuItem: playbackModel.handleMenuItem(item.id)
onHandleMenuItem: {
playbackModel.handleMenuItem(itemId)
}
}
}
}

View file

@ -271,7 +271,7 @@ Item {
onHandleMenuItem: {
if (root.resourceItemModel) {
root.resourceItemModel.handleMenuItem(item.id)
root.resourceItemModel.handleMenuItem(itemId)
}
}