diff --git a/src/appshell/iappshellconfiguration.h b/src/appshell/iappshellconfiguration.h index b7d6c1965f113..6d74948faf4c0 100644 --- a/src/appshell/iappshellconfiguration.h +++ b/src/appshell/iappshellconfiguration.h @@ -23,7 +23,7 @@ #define MU_APPSHELL_IAPPSHELLCONFIGURATION_H #include "modularity/imoduleinterface.h" -#include "types/retval.h" +#include "types/ret.h" #include "io/path.h" #include "appshelltypes.h" @@ -42,9 +42,11 @@ class IAppShellConfiguration : MODULE_EXPORT_INTERFACE virtual StartupModeType startupModeType() const = 0; virtual void setStartupModeType(StartupModeType type) = 0; + virtual muse::async::Notification startupModeTypeChanged() const = 0; virtual muse::io::path_t startupScorePath() const = 0; virtual void setStartupScorePath(const muse::io::path_t& scorePath) = 0; + virtual muse::async::Notification startupScorePathChanged() const = 0; virtual muse::io::path_t userDataPath() const = 0; diff --git a/src/appshell/internal/appshellconfiguration.cpp b/src/appshell/internal/appshellconfiguration.cpp index 68099a3366308..93fdc9c07df23 100644 --- a/src/appshell/internal/appshellconfiguration.cpp +++ b/src/appshell/internal/appshellconfiguration.cpp @@ -63,7 +63,14 @@ void AppShellConfiguration::init() settings()->setDefaultValue(HAS_COMPLETED_FIRST_LAUNCH_SETUP, Val(false)); settings()->setDefaultValue(STARTUP_MODE_TYPE, Val(StartupModeType::StartEmpty)); + settings()->valueChanged(STARTUP_MODE_TYPE).onReceive(this, [this](const Val&) { + m_startupModeTypeChanged.notify(); + }); + settings()->setDefaultValue(STARTUP_SCORE_PATH, Val(projectConfiguration()->myFirstProjectPath().toStdString())); + settings()->valueChanged(STARTUP_SCORE_PATH).onReceive(this, [this](const Val&) { + m_startupScorePathChanged.notify(); + }); fileSystem()->makePath(sessionDataPath()); } @@ -88,6 +95,11 @@ void AppShellConfiguration::setStartupModeType(StartupModeType type) settings()->setSharedValue(STARTUP_MODE_TYPE, Val(type)); } +async::Notification AppShellConfiguration::startupModeTypeChanged() const +{ + return m_startupModeTypeChanged; +} + muse::io::path_t AppShellConfiguration::startupScorePath() const { return settings()->value(STARTUP_SCORE_PATH).toString(); @@ -98,6 +110,11 @@ void AppShellConfiguration::setStartupScorePath(const muse::io::path_t& scorePat settings()->setSharedValue(STARTUP_SCORE_PATH, Val(scorePath.toStdString())); } +async::Notification AppShellConfiguration::startupScorePathChanged() const +{ + return m_startupScorePathChanged; +} + muse::io::path_t AppShellConfiguration::userDataPath() const { return globalConfiguration()->userDataPath(); diff --git a/src/appshell/internal/appshellconfiguration.h b/src/appshell/internal/appshellconfiguration.h index e21a79c44138e..291c6602f7a11 100644 --- a/src/appshell/internal/appshellconfiguration.h +++ b/src/appshell/internal/appshellconfiguration.h @@ -61,9 +61,11 @@ class AppShellConfiguration : public IAppShellConfiguration, public muse::Inject StartupModeType startupModeType() const override; void setStartupModeType(StartupModeType type) override; + muse::async::Notification startupModeTypeChanged() const override; muse::io::path_t startupScorePath() const override; void setStartupScorePath(const muse::io::path_t& scorePath) override; + muse::async::Notification startupScorePathChanged() const override; muse::io::path_t userDataPath() const override; @@ -111,6 +113,9 @@ class AppShellConfiguration : public IAppShellConfiguration, public muse::Inject muse::io::paths_t parseSessionProjectsPaths(const QByteArray& json) const; QString m_preferencesDialogCurrentPageId; + + muse::async::Notification m_startupModeTypeChanged; + muse::async::Notification m_startupScorePathChanged; }; } diff --git a/src/appshell/qml/Preferences/BraillePreferencesPage.qml b/src/appshell/qml/Preferences/BraillePreferencesPage.qml index 575eae2124e6b..503549f054942 100644 --- a/src/appshell/qml/Preferences/BraillePreferencesPage.qml +++ b/src/appshell/qml/Preferences/BraillePreferencesPage.qml @@ -34,6 +34,10 @@ PreferencesPage { id: preferencesModel } + Component.onCompleted: { + preferencesModel.load() + } + Column { width: parent.width spacing: root.sectionsSpacing diff --git a/src/appshell/qml/Preferences/ImportPreferencesPage.qml b/src/appshell/qml/Preferences/ImportPreferencesPage.qml index 1357912d9e156..3fd17c82cafe7 100644 --- a/src/appshell/qml/Preferences/ImportPreferencesPage.qml +++ b/src/appshell/qml/Preferences/ImportPreferencesPage.qml @@ -42,6 +42,7 @@ PreferencesPage { spacing: root.sectionsSpacing ImportStyleSection { + id: importStyleSection styleFileImportPath: importPreferencesModel.styleFileImportPath fileChooseTitle: importPreferencesModel.styleChooseTitle() filePathFilter: importPreferencesModel.stylePathFilter() @@ -145,4 +146,8 @@ PreferencesPage { } } } + + function reset() { + importStyleSection.reset() + } } diff --git a/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml b/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml index 1b5fd385cc424..13dce35a123af 100644 --- a/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml +++ b/src/appshell/qml/Preferences/NoteInputPreferencesPage.qml @@ -30,6 +30,10 @@ import "internal" PreferencesPage { id: root + Component.onCompleted: { + noteInputModel.load() + } + NoteInputPreferencesModel { id: noteInputModel } diff --git a/src/appshell/qml/Preferences/PreferencesDialog.qml b/src/appshell/qml/Preferences/PreferencesDialog.qml index 1315ca75e4b11..8a6774d9f1058 100644 --- a/src/appshell/qml/Preferences/PreferencesDialog.qml +++ b/src/appshell/qml/Preferences/PreferencesDialog.qml @@ -149,6 +149,10 @@ StyledDialogView { navigation.order: 100000 onRevertFactorySettingsRequested: { + if (!preferencesModel.askForConfirmationOfPreferencesReset()) { + return; + } + var pages = preferencesModel.availablePages() for (var i in pages) { diff --git a/src/appshell/qml/Preferences/UpdatePreferencesPage.qml b/src/appshell/qml/Preferences/UpdatePreferencesPage.qml index db27e2eda6472..cd90ca569cc1e 100644 --- a/src/appshell/qml/Preferences/UpdatePreferencesPage.qml +++ b/src/appshell/qml/Preferences/UpdatePreferencesPage.qml @@ -34,6 +34,10 @@ PreferencesPage { id: updateModel } + Component.onCompleted: { + updateModel.load() + } + Column { width: parent.width spacing: root.sectionsSpacing diff --git a/src/appshell/qml/Preferences/internal/ImportStyleSection.qml b/src/appshell/qml/Preferences/internal/ImportStyleSection.qml index 63cdcd54a116b..3989ed37670ee 100644 --- a/src/appshell/qml/Preferences/internal/ImportStyleSection.qml +++ b/src/appshell/qml/Preferences/internal/ImportStyleSection.qml @@ -41,7 +41,12 @@ BaseSection { QtObject { id: prv - property bool useStyleFile: root.styleFileImportPath !== "" + property bool useStyleFileExplicitlySet: root.styleFileImportPath !== "" + property bool useStyleFile: prv.useStyleFileExplicitlySet || root.styleFileImportPath !== "" + } + + function reset() { + prv.useStyleFileExplicitlySet = false } RoundedRadioButton { @@ -57,7 +62,7 @@ BaseSection { navigation.column: 0 onToggled: { - prv.useStyleFile = false + prv.useStyleFileExplicitlySet = false root.styleFileImportPathChangeRequested("") } } @@ -81,7 +86,7 @@ BaseSection { navigation.column: 0 onToggled: { - prv.useStyleFile = true + prv.useStyleFileExplicitlySet = true } } diff --git a/src/appshell/view/preferences/advancedpreferencesmodel.cpp b/src/appshell/view/preferences/advancedpreferencesmodel.cpp index 6496a07b98cd6..2100d8ccd42f2 100644 --- a/src/appshell/view/preferences/advancedpreferencesmodel.cpp +++ b/src/appshell/view/preferences/advancedpreferencesmodel.cpp @@ -58,7 +58,7 @@ bool AdvancedPreferencesModel::setData(const QModelIndex& index, const QVariant& switch (role) { case ValueRole: - changeVal(index.row(), value); + changeVal(index.row(), Val::fromQVariant(value)); emit dataChanged(index, index, { ValueRole }); return true; default: @@ -96,20 +96,48 @@ void AdvancedPreferencesModel::load() for (auto it = items.cbegin(); it != items.cend(); ++it) { if (it->second.canBeManuallyEdited) { m_items << it->second; + + muse::Settings::Key key = it->second.key; + settings()->valueChanged(key).onReceive(this, [this, key](const Val& val) { + QModelIndex index = findIndex(key); + if (!index.isValid() || m_items[index.row()].value == val) { + return; + } + + changeModelVal(m_items[index.row()], val); + emit dataChanged(index, index, { ValueRole }); + }); } } endResetModel(); } -void AdvancedPreferencesModel::changeVal(int index, QVariant newVal) +QModelIndex AdvancedPreferencesModel::findIndex(const muse::Settings::Key& key) +{ + for (int i = 0; i < m_items.size(); ++i) { + if (m_items[i].key == key) { + return index(i, 0); + } + } + return QModelIndex(); +} + +void AdvancedPreferencesModel::changeVal(int index, const Val& newVal) { Settings::Item& item = m_items[index]; + changeModelVal(item, newVal); + settings()->setSharedValue(item.key, item.value); +} + +void AdvancedPreferencesModel::changeModelVal(Settings::Item& item, const Val& newVal) +{ + if (item.value == newVal) { + return; + } Val::Type type = item.value.type(); - item.value = Val::fromQVariant(newVal); + item.value = newVal; item.value.setType(type); - - settings()->setSharedValue(item.key, item.value); } void AdvancedPreferencesModel::resetToDefault() @@ -117,7 +145,7 @@ void AdvancedPreferencesModel::resetToDefault() beginResetModel(); for (int i = 0; i < m_items.size(); ++i) { - changeVal(i, m_items[i].defaultValue.toQVariant()); + changeVal(i, m_items[i].defaultValue); } endResetModel(); diff --git a/src/appshell/view/preferences/advancedpreferencesmodel.h b/src/appshell/view/preferences/advancedpreferencesmodel.h index 252f545cab552..f6fa00e0b6aec 100644 --- a/src/appshell/view/preferences/advancedpreferencesmodel.h +++ b/src/appshell/view/preferences/advancedpreferencesmodel.h @@ -24,10 +24,11 @@ #include +#include "async/asyncable.h" #include "settings.h" namespace mu::appshell { -class AdvancedPreferencesModel : public QAbstractListModel +class AdvancedPreferencesModel : public QAbstractListModel, public muse::async::Asyncable { Q_OBJECT @@ -53,7 +54,9 @@ class AdvancedPreferencesModel : public QAbstractListModel MaxValueRole }; - void changeVal(int index, QVariant newVal); + QModelIndex findIndex(const muse::Settings::Key& key); + void changeVal(int index, const muse::Val& newVal); + void changeModelVal(muse::Settings::Item& item, const muse::Val& newVal); QString typeToString(muse::Val::Type type) const; QList m_items; diff --git a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp index e159964a330cb..9be02db3429c6 100644 --- a/src/appshell/view/preferences/audiomidipreferencesmodel.cpp +++ b/src/appshell/view/preferences/audiomidipreferencesmodel.cpp @@ -92,6 +92,10 @@ void AudioMidiPreferencesModel::init() emit midiOutputDeviceIdChanged(); }); + midiConfiguration()->useMIDI20OutputChanged().onReceive(this, [this](bool) { + emit useMIDI20OutputChanged(); + }); + playbackConfiguration()->muteHiddenInstrumentsChanged().onReceive(this, [this](bool mute) { emit muteHiddenInstrumentsChanged(mute); }); diff --git a/src/appshell/view/preferences/braillepreferencesmodel.cpp b/src/appshell/view/preferences/braillepreferencesmodel.cpp index e3d675b0aa0d9..beb97263d3d57 100644 --- a/src/appshell/view/preferences/braillepreferencesmodel.cpp +++ b/src/appshell/view/preferences/braillepreferencesmodel.cpp @@ -32,6 +32,21 @@ BraillePreferencesModel::BraillePreferencesModel(QObject* parent) { } +void BraillePreferencesModel::load() +{ + brailleConfiguration()->braillePanelEnabledChanged().onNotify(this, [this]() { + emit braillePanelEnabledChanged(braillePanelEnabled()); + }); + + brailleConfiguration()->intervalDirectionChanged().onNotify(this, [this]() { + emit intervalDirectionChanged(intervalDirection()); + }); + + brailleConfiguration()->brailleTableChanged().onNotify(this, [this]() { + emit brailleTableChanged(brailleTable()); + }); +} + bool BraillePreferencesModel::braillePanelEnabled() const { return brailleConfiguration()->braillePanelEnabled(); diff --git a/src/appshell/view/preferences/braillepreferencesmodel.h b/src/appshell/view/preferences/braillepreferencesmodel.h index 6859727494a07..8c3fad0f98045 100644 --- a/src/appshell/view/preferences/braillepreferencesmodel.h +++ b/src/appshell/view/preferences/braillepreferencesmodel.h @@ -25,11 +25,12 @@ #include +#include "async/asyncable.h" #include "modularity/ioc.h" #include "braille/ibrailleconfiguration.h" namespace mu::appshell { -class BraillePreferencesModel : public QObject, public muse::Injectable +class BraillePreferencesModel : public QObject, public muse::Injectable, public muse::async::Asyncable { Q_OBJECT @@ -42,6 +43,8 @@ class BraillePreferencesModel : public QObject, public muse::Injectable public: explicit BraillePreferencesModel(QObject* parent = nullptr); + Q_INVOKABLE void load(); + bool braillePanelEnabled() const; QString brailleTable() const; int intervalDirection() const; diff --git a/src/appshell/view/preferences/canvaspreferencesmodel.cpp b/src/appshell/view/preferences/canvaspreferencesmodel.cpp index 1c284e165a64e..4c3dc26de3c3b 100644 --- a/src/appshell/view/preferences/canvaspreferencesmodel.cpp +++ b/src/appshell/view/preferences/canvaspreferencesmodel.cpp @@ -37,6 +37,25 @@ void CanvasPreferencesModel::load() setupConnections(); } +void CanvasPreferencesModel::setupConnections() +{ + notationConfiguration()->defaultZoomChanged().onNotify(this, [this]() { + emit defaultZoomChanged(); + }); + notationConfiguration()->mouseZoomPrecisionChanged().onNotify(this, [this]() { + emit mouseZoomPrecisionChanged(); + }); + notationConfiguration()->canvasOrientation().ch.onReceive(this, [this](muse::Orientation) { + emit scrollPagesOrientationChanged(); + }); + notationConfiguration()->isLimitCanvasScrollAreaChanged().onNotify(this, [this]() { + emit limitScrollAreaChanged(); + }); + notationConfiguration()->selectionProximityChanged().onReceive(this, [this](int selectionProximity) { + emit selectionProximityChanged(selectionProximity); + }); +} + QVariantList CanvasPreferencesModel::zoomTypes() const { QVariantList types = { @@ -140,13 +159,6 @@ void CanvasPreferencesModel::setSelectionProximity(int proximity) emit selectionProximityChanged(proximity); } -void CanvasPreferencesModel::setupConnections() -{ - notationConfiguration()->canvasOrientation().ch.onReceive(this, [this](muse::Orientation) { - emit scrollPagesOrientationChanged(); - }); -} - ZoomType CanvasPreferencesModel::defaultZoomType() const { return notationConfiguration()->defaultZoomType(); diff --git a/src/appshell/view/preferences/generalpreferencesmodel.cpp b/src/appshell/view/preferences/generalpreferencesmodel.cpp index b14b6687202df..49fce019364ab 100644 --- a/src/appshell/view/preferences/generalpreferencesmodel.cpp +++ b/src/appshell/view/preferences/generalpreferencesmodel.cpp @@ -45,6 +45,14 @@ void GeneralPreferencesModel::load() languagesService()->needRestartToApplyLanguageChangeChanged().onReceive(this, [this](bool need) { setIsNeedRestart(need); }); + + configuration()->startupModeTypeChanged().onNotify(this, [this]() { + emit startupModesChanged(); + }); + + configuration()->startupScorePathChanged().onNotify(this, [this]() { + emit startupModesChanged(); + }); } void GeneralPreferencesModel::checkUpdateForCurrentLanguage() @@ -244,6 +252,5 @@ void GeneralPreferencesModel::setStartupScorePath(const QString& scorePath) } configuration()->setStartupScorePath(scorePath); - emit startupModesChanged(); } diff --git a/src/appshell/view/preferences/importpreferencesmodel.cpp b/src/appshell/view/preferences/importpreferencesmodel.cpp index a1c323e3c35d5..fe0b78710883e 100644 --- a/src/appshell/view/preferences/importpreferencesmodel.cpp +++ b/src/appshell/view/preferences/importpreferencesmodel.cpp @@ -36,6 +36,41 @@ ImportPreferencesModel::ImportPreferencesModel(QObject* parent) void ImportPreferencesModel::load() { + notationConfiguration()->styleFileImportPathChanged().onReceive(this, [this](const std::string& val) { + emit styleFileImportPathChanged(QString::fromStdString(val)); + }); + + oveConfiguration()->importOvertureCharsetChanged().onReceive(this, [this](const std::string& val) { + emit currentOvertureCharsetChanged(QString::fromStdString(val)); + }); + + musicXmlConfiguration()->importLayoutChanged().onReceive(this, [this](bool val) { + emit importLayoutChanged(val); + }); + + musicXmlConfiguration()->importBreaksChanged().onReceive(this, [this](bool val) { + emit importBreaksChanged(val); + }); + + musicXmlConfiguration()->needUseDefaultFontChanged().onReceive(this, [this](bool val) { + emit needUseDefaultFontChanged(val); + }); + + musicXmlConfiguration()->inferTextTypeChanged().onReceive(this, [this](bool val) { + emit inferTextTypeChanged(val); + }); + + midiImportExportConfiguration()->midiShortestNoteChanged().onReceive(this, [this](int val) { + emit currentShortestNoteChanged(val); + }); + + meiConfiguration()->meiImportLayoutChanged().onReceive(this, [this](bool val) { + emit meiImportLayoutChanged(val); + }); + + musicXmlConfiguration()->needAskAboutApplyingNewStyleChanged().onReceive(this, [this](bool val) { + emit needAskAboutApplyingNewStyleChanged(val); + }); } QVariantList ImportPreferencesModel::charsets() const diff --git a/src/appshell/view/preferences/noteinputpreferencesmodel.cpp b/src/appshell/view/preferences/noteinputpreferencesmodel.cpp index 3637bb07d9936..467e604065f83 100644 --- a/src/appshell/view/preferences/noteinputpreferencesmodel.cpp +++ b/src/appshell/view/preferences/noteinputpreferencesmodel.cpp @@ -31,6 +31,45 @@ NoteInputPreferencesModel::NoteInputPreferencesModel(QObject* parent) { } +void NoteInputPreferencesModel::load() +{ + shortcutsConfiguration()->advanceToNextNoteOnKeyReleaseChanged().onReceive(this, [this](bool value) { + emit advanceToNextNoteOnKeyReleaseChanged(value); + }); + + notationConfiguration()->colorNotesOutsideOfUsablePitchRangeChanged().onReceive(this, [this](bool value) { + emit colorNotesOutsideOfUsablePitchRangeChanged(value); + }); + + notationConfiguration()->warnGuitarBendsChanged().onReceive(this, [this](bool value) { + emit warnGuitarBendsChanged(value); + }); + + notationConfiguration()->delayBetweenNotesInRealTimeModeMillisecondsChanged().onReceive(this, [this](int value) { + emit delayBetweenNotesInRealTimeModeMillisecondsChanged(value); + }); + + playbackConfiguration()->playNotesWhenEditingChanged().onReceive(this, [this](bool value) { + emit playNotesWhenEditingChanged(value); + }); + + notationConfiguration()->notePlayDurationMillisecondsChanged().onReceive(this, [this](int value) { + emit notePlayDurationMillisecondsChanged(value); + }); + + playbackConfiguration()->playChordWhenEditingChanged().onReceive(this, [this](bool value) { + emit playChordWhenEditingChanged(value); + }); + + playbackConfiguration()->playHarmonyWhenEditingChanged().onReceive(this, [this](bool value) { + emit playChordSymbolWhenEditingChanged(value); + }); + + engravingConfiguration()->dynamicsApplyToAllVoicesChanged().onReceive(this, [this](bool value) { + emit dynamicsApplyToAllVoicesChanged(value); + }); +} + bool NoteInputPreferencesModel::advanceToNextNoteOnKeyRelease() const { return shortcutsConfiguration()->advanceToNextNoteOnKeyRelease(); diff --git a/src/appshell/view/preferences/noteinputpreferencesmodel.h b/src/appshell/view/preferences/noteinputpreferencesmodel.h index 78c77ea6da1ee..b7f67b145afc6 100644 --- a/src/appshell/view/preferences/noteinputpreferencesmodel.h +++ b/src/appshell/view/preferences/noteinputpreferencesmodel.h @@ -24,6 +24,7 @@ #include +#include "async/asyncable.h" #include "modularity/ioc.h" #include "engraving/iengravingconfiguration.h" #include "shortcuts/ishortcutsconfiguration.h" @@ -31,7 +32,7 @@ #include "playback/iplaybackconfiguration.h" namespace mu::appshell { -class NoteInputPreferencesModel : public QObject, public muse::Injectable +class NoteInputPreferencesModel : public QObject, public muse::Injectable, public muse::async::Asyncable { Q_OBJECT @@ -61,6 +62,8 @@ class NoteInputPreferencesModel : public QObject, public muse::Injectable public: explicit NoteInputPreferencesModel(QObject* parent = nullptr); + Q_INVOKABLE void load(); + bool advanceToNextNoteOnKeyRelease() const; bool colorNotesOutsideOfUsablePitchRange() const; bool warnGuitarBends() const; diff --git a/src/appshell/view/preferences/preferencesmodel.cpp b/src/appshell/view/preferences/preferencesmodel.cpp index 48f6415741d77..566073f7b63b0 100644 --- a/src/appshell/view/preferences/preferencesmodel.cpp +++ b/src/appshell/view/preferences/preferencesmodel.cpp @@ -204,6 +204,21 @@ void PreferencesModel::load(const QString& currentPageId) endResetModel(); } +bool PreferencesModel::askForConfirmationOfPreferencesReset() +{ + std::string title = muse::trc("appshell", "Are you sure you want to reset preferences?"); + std::string question = muse::trc("appshell", "This action will reset all your app preferences and delete all custom palettes and custom shortcuts.\n\n" + "This action will not delete any of your scores.\n\n" + "This action cannot be undone."); + + muse::IInteractive::ButtonData cancelBtn = interactive()->buttonData(muse::IInteractive::Button::Cancel); + muse::IInteractive::ButtonData resetBtn = interactive()->buttonData(muse::IInteractive::Button::Reset); + cancelBtn.accent = true; + + muse::IInteractive::Result result = interactive()->warning(title, question, { cancelBtn, resetBtn }, cancelBtn.btn); + return result.standardButton() == muse::IInteractive::Button::Reset; +} + void PreferencesModel::resetFactorySettings() { static constexpr bool KEEP_DEFAULT_SETTINGS = true; diff --git a/src/appshell/view/preferences/preferencesmodel.h b/src/appshell/view/preferences/preferencesmodel.h index 64497b6fa2b59..91abb00ffe9b3 100644 --- a/src/appshell/view/preferences/preferencesmodel.h +++ b/src/appshell/view/preferences/preferencesmodel.h @@ -31,6 +31,7 @@ #include "iappshellconfiguration.h" #include "preferencepageitem.h" +#include "iinteractive.h" namespace mu::appshell { class PreferencesModel : public QAbstractItemModel, public muse::Injectable @@ -42,6 +43,7 @@ class PreferencesModel : public QAbstractItemModel, public muse::Injectable muse::Inject dispatcher = { this }; muse::Inject configuration = { this }; muse::Inject actionsRegister = { this }; + muse::Inject interactive = { this }; public: explicit PreferencesModel(QObject* parent = nullptr); @@ -57,6 +59,7 @@ class PreferencesModel : public QAbstractItemModel, public muse::Injectable QString currentPageId() const; Q_INVOKABLE void load(const QString& currentPageId); + Q_INVOKABLE bool askForConfirmationOfPreferencesReset(); Q_INVOKABLE void resetFactorySettings(); Q_INVOKABLE void apply(); Q_INVOKABLE void cancel(); diff --git a/src/appshell/view/preferences/scorepreferencesmodel.cpp b/src/appshell/view/preferences/scorepreferencesmodel.cpp index 2df97be433e77..877398a31ada4 100644 --- a/src/appshell/view/preferences/scorepreferencesmodel.cpp +++ b/src/appshell/view/preferences/scorepreferencesmodel.cpp @@ -100,6 +100,19 @@ void ScorePreferencesModel::load() }; endResetModel(); + + notationConfiguration()->scoreOrderListPathsChanged().onNotify(this, [this]() { + setPath(DefaultFileType::FirstScoreOrderList, firstScoreOrderListPath()); + setPath(DefaultFileType::SecondScoreOrderList, secondScoreOrderListPath()); + }); + + notationConfiguration()->defaultStyleFilePathChanged().onReceive(this, [this](const io::path_t& val) { + setPath(DefaultFileType::Style, val.toQString()); + }); + + notationConfiguration()->partStyleFilePathChanged().onReceive(this, [this](const io::path_t& val) { + setPath(DefaultFileType::PartStyle, val.toQString()); + }); } void ScorePreferencesModel::savePath(ScorePreferencesModel::DefaultFileType fileType, const QString& path) diff --git a/src/appshell/view/preferences/updatepreferencesmodel.cpp b/src/appshell/view/preferences/updatepreferencesmodel.cpp index c8be9ffed7a95..20b1f66191056 100644 --- a/src/appshell/view/preferences/updatepreferencesmodel.cpp +++ b/src/appshell/view/preferences/updatepreferencesmodel.cpp @@ -31,6 +31,13 @@ UpdatePreferencesModel::UpdatePreferencesModel(QObject* parent) { } +void UpdatePreferencesModel::load() +{ + updateConfiguration()->needCheckForUpdateChanged().onNotify(this, [this]() { + emit needCheckForNewAppVersionChanged(needCheckForNewAppVersion()); + }); +} + bool UpdatePreferencesModel::isAppUpdatable() const { return updateConfiguration()->isAppUpdatable(); diff --git a/src/appshell/view/preferences/updatepreferencesmodel.h b/src/appshell/view/preferences/updatepreferencesmodel.h index c367e4c41a998..a6f2f78eefcbb 100644 --- a/src/appshell/view/preferences/updatepreferencesmodel.h +++ b/src/appshell/view/preferences/updatepreferencesmodel.h @@ -24,11 +24,12 @@ #include +#include "async/asyncable.h" #include "modularity/ioc.h" #include "update/iupdateconfiguration.h" namespace mu::appshell { -class UpdatePreferencesModel : public QObject, public muse::Injectable +class UpdatePreferencesModel : public QObject, public muse::Injectable, public muse::async::Asyncable { Q_OBJECT @@ -40,6 +41,8 @@ class UpdatePreferencesModel : public QObject, public muse::Injectable public: explicit UpdatePreferencesModel(QObject* parent = nullptr); + Q_INVOKABLE void load(); + bool needCheckForNewAppVersion() const; Q_INVOKABLE bool isAppUpdatable() const; diff --git a/src/engraving/iengravingconfiguration.h b/src/engraving/iengravingconfiguration.h index 986673444ba72..961f7d88f9a71 100644 --- a/src/engraving/iengravingconfiguration.h +++ b/src/engraving/iengravingconfiguration.h @@ -44,9 +44,11 @@ class IEngravingConfiguration : MODULE_EXPORT_INTERFACE virtual muse::io::path_t defaultStyleFilePath() const = 0; virtual void setDefaultStyleFilePath(const muse::io::path_t& path) = 0; + virtual muse::async::Channel defaultStyleFilePathChanged() const = 0; virtual muse::io::path_t partStyleFilePath() const = 0; virtual void setPartStyleFilePath(const muse::io::path_t& path) = 0; + virtual muse::async::Channel partStyleFilePathChanged() const = 0; virtual SizeF defaultPageSize() const = 0; @@ -77,6 +79,7 @@ class IEngravingConfiguration : MODULE_EXPORT_INTERFACE virtual bool dynamicsApplyToAllVoices() const = 0; virtual void setDynamicsApplyToAllVoices(bool v) = 0; + virtual muse::async::Channel dynamicsApplyToAllVoicesChanged() const = 0; virtual Color formattingColor() const = 0; virtual muse::async::Channel formattingColorChanged() const = 0; diff --git a/src/engraving/internal/engravingconfiguration.cpp b/src/engraving/internal/engravingconfiguration.cpp index 608518e737672..511ed9ceca640 100644 --- a/src/engraving/internal/engravingconfiguration.cpp +++ b/src/engraving/internal/engravingconfiguration.cpp @@ -70,6 +70,14 @@ void EngravingConfiguration::init() "#6038FC", // "all voices" }; + settings()->valueChanged(DEFAULT_STYLE_FILE_PATH).onReceive(this, [this](const Val& val) { + m_defaultStyleFilePathChanged.send(val.toPath()); + }); + + settings()->valueChanged(PART_STYLE_FILE_PATH).onReceive(this, [this](const Val& val) { + m_partStyleFilePathChanged.send(val.toPath()); + }); + settings()->setDefaultValue(INVERT_SCORE_COLOR, Val(false)); settings()->valueChanged(INVERT_SCORE_COLOR).onReceive(nullptr, [this](const Val&) { m_scoreInversionChanged.notify(); @@ -104,6 +112,9 @@ void EngravingConfiguration::init() VOICE_COLORS[ALL_VOICES_IDX] = VoiceColor { std::move(ALL_VOICES_COLOR), currentColor }; settings()->setDefaultValue(DYNAMICS_APPLY_TO_ALL_VOICES, Val(true)); + settings()->valueChanged(DYNAMICS_APPLY_TO_ALL_VOICES).onReceive(this, [this](const Val& val) { + m_dynamicsApplyToAllVoicesChanged.send(val.toBool()); + }); settings()->setDefaultValue(FORMATTING_COLOR, Val(Color("#A0A0A4").toQColor())); settings()->setDescription(FORMATTING_COLOR, muse::trc("engraving", "Formatting color")); @@ -135,6 +146,11 @@ void EngravingConfiguration::setDefaultStyleFilePath(const muse::io::path_t& pat settings()->setSharedValue(DEFAULT_STYLE_FILE_PATH, Val(path.toStdString())); } +async::Channel EngravingConfiguration::defaultStyleFilePathChanged() const +{ + return m_defaultStyleFilePathChanged; +} + muse::io::path_t EngravingConfiguration::partStyleFilePath() const { return settings()->value(PART_STYLE_FILE_PATH).toPath(); @@ -145,6 +161,11 @@ void EngravingConfiguration::setPartStyleFilePath(const muse::io::path_t& path) settings()->setSharedValue(PART_STYLE_FILE_PATH, Val(path.toStdString())); } +async::Channel EngravingConfiguration::partStyleFilePathChanged() const +{ + return m_partStyleFilePathChanged; +} + static bool defaultPageSizeIsLetter() { // try PAPERSIZE environment variable @@ -304,6 +325,11 @@ void EngravingConfiguration::setDynamicsApplyToAllVoices(bool v) settings()->setSharedValue(DYNAMICS_APPLY_TO_ALL_VOICES, Val(v)); } +muse::async::Channel EngravingConfiguration::dynamicsApplyToAllVoicesChanged() const +{ + return m_dynamicsApplyToAllVoicesChanged; +} + muse::async::Notification EngravingConfiguration::scoreInversionChanged() const { return m_scoreInversionChanged; diff --git a/src/engraving/internal/engravingconfiguration.h b/src/engraving/internal/engravingconfiguration.h index 81b862a872ffc..e89437848f854 100644 --- a/src/engraving/internal/engravingconfiguration.h +++ b/src/engraving/internal/engravingconfiguration.h @@ -50,9 +50,11 @@ class EngravingConfiguration : public IEngravingConfiguration, public muse::Inje muse::io::path_t defaultStyleFilePath() const override; void setDefaultStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel defaultStyleFilePathChanged() const override; muse::io::path_t partStyleFilePath() const override; void setPartStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel partStyleFilePathChanged() const override; SizeF defaultPageSize() const override; @@ -84,6 +86,7 @@ class EngravingConfiguration : public IEngravingConfiguration, public muse::Inje bool dynamicsApplyToAllVoices() const override; void setDynamicsApplyToAllVoices(bool v) override; + muse::async::Channel dynamicsApplyToAllVoicesChanged() const override; muse::async::Notification scoreInversionChanged() const override; @@ -113,8 +116,11 @@ class EngravingConfiguration : public IEngravingConfiguration, public muse::Inje private: muse::async::Channel m_voiceColorChanged; muse::async::Notification m_scoreInversionChanged; + muse::async::Channel m_dynamicsApplyToAllVoicesChanged; muse::async::Channel m_formattingColorChanged; muse::async::Channel m_unlinkedColorChanged; + muse::async::Channel m_defaultStyleFilePathChanged; + muse::async::Channel m_partStyleFilePathChanged; muse::ValNt m_debuggingOptions; diff --git a/src/engraving/tests/mocks/engravingconfigurationmock.h b/src/engraving/tests/mocks/engravingconfigurationmock.h index 6cb76baad624e..5b3bce37433bc 100644 --- a/src/engraving/tests/mocks/engravingconfigurationmock.h +++ b/src/engraving/tests/mocks/engravingconfigurationmock.h @@ -34,9 +34,11 @@ class EngravingConfigurationMock : public IEngravingConfiguration MOCK_METHOD(muse::io::path_t, defaultStyleFilePath, (), (const, override)); MOCK_METHOD(void, setDefaultStyleFilePath, (const muse::io::path_t&), (override)); + MOCK_METHOD(muse::async::Channel, defaultStyleFilePathChanged, (), (const, override)); MOCK_METHOD(muse::io::path_t, partStyleFilePath, (), (const, override)); MOCK_METHOD(void, setPartStyleFilePath, (const muse::io::path_t&), (override)); + MOCK_METHOD(muse::async::Channel, partStyleFilePathChanged, (), (const, override)); MOCK_METHOD(SizeF, defaultPageSize, (), (const, override)); @@ -63,6 +65,7 @@ class EngravingConfigurationMock : public IEngravingConfiguration MOCK_METHOD(bool, dynamicsApplyToAllVoices, (), (const, override)); MOCK_METHOD(void, setDynamicsApplyToAllVoices, (bool), (override)); + MOCK_METHOD((muse::async::Channel), dynamicsApplyToAllVoicesChanged, (), (const, override)); MOCK_METHOD(bool, scoreInversionEnabled, (), (const, override)); MOCK_METHOD(void, setScoreInversionEnabled, (bool), (override)); diff --git a/src/framework/audio/internal/audioconfiguration.cpp b/src/framework/audio/internal/audioconfiguration.cpp index 415be6850aa0f..6cf4681f6019d 100644 --- a/src/framework/audio/internal/audioconfiguration.cpp +++ b/src/framework/audio/internal/audioconfiguration.cpp @@ -70,6 +70,7 @@ void AudioConfiguration::init() settings()->setDefaultValue(AUDIO_API_KEY, Val("Core Audio")); + settings()->setDefaultValue(AUDIO_OUTPUT_DEVICE_ID_KEY, Val(DEFAULT_DEVICE_ID)); settings()->valueChanged(AUDIO_OUTPUT_DEVICE_ID_KEY).onReceive(nullptr, [this](const Val&) { m_audioOutputDeviceIdChanged.notify(); }); diff --git a/src/framework/audio/internal/audioconfiguration.h b/src/framework/audio/internal/audioconfiguration.h index 453c68b2f8cc3..e06b1fa1b8eca 100644 --- a/src/framework/audio/internal/audioconfiguration.h +++ b/src/framework/audio/internal/audioconfiguration.h @@ -79,6 +79,8 @@ class AudioConfiguration : public IAudioConfiguration, public Injectable bool shouldMeasureInputLag() const override; private: + static constexpr char DEFAULT_DEVICE_ID[] = "default"; // Must match DEFAULT_DEVICE_ID in wasapiaudiodriver.cpp and possibly others! + void updateSamplesToPreallocate(); async::Channel m_soundFontDirsChanged; diff --git a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp index 7b03f56b3a84b..068d8cc807d8f 100644 --- a/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp +++ b/src/framework/audio/internal/platform/win/wasapiaudiodriver.cpp @@ -34,7 +34,7 @@ using namespace winrt; using namespace muse; using namespace muse::audio; -static constexpr char DEFAULT_DEVICE_ID[] = "default"; +static constexpr char DEFAULT_DEVICE_ID[] = "default"; // Must match DEFAULT_DEVICE_ID in audioconfiguration.cpp and possibly others! inline int refTimeToSamples(const REFERENCE_TIME& t, double sampleRate) noexcept { diff --git a/src/framework/global/settings.cpp b/src/framework/global/settings.cpp index 2b65d02e7f928..8fea244303dc5 100644 --- a/src/framework/global/settings.cpp +++ b/src/framework/global/settings.cpp @@ -95,6 +95,13 @@ void Settings::reset(bool keepDefaultSettings, bool notifyAboutChanges) m_settings->clear(); m_isTransactionStarted = false; + + std::vector locallyAddedKeys; + for (auto it = m_localSettings.begin(); it != m_localSettings.end(); ++it) { + if (m_items.count(it->first) == 0) { + locallyAddedKeys.push_back(it->first); + } + } m_localSettings.clear(); if (!keepDefaultSettings) { @@ -112,6 +119,10 @@ void Settings::reset(bool keepDefaultSettings, bool notifyAboutChanges) Channel& channel = findChannel(it->first); channel.send(it->second.value); } + for (auto it = locallyAddedKeys.cbegin(); it != locallyAddedKeys.cend(); ++it) { + Channel& channel = findChannel(*it); + channel.send(Val()); + } } static Val compat_QVariantToVal(const QVariant& var) diff --git a/src/framework/languages/internal/languagesservice.cpp b/src/framework/languages/internal/languagesservice.cpp index 3f1197fe6b9cb..b429fb1bdbd4c 100644 --- a/src/framework/languages/internal/languagesservice.cpp +++ b/src/framework/languages/internal/languagesservice.cpp @@ -64,9 +64,14 @@ void LanguagesService::init() ValCh languageCode = configuration()->currentLanguageCode(); setCurrentLanguage(languageCode.val); - languageCode.ch.onReceive(this, [this](const QString&) { + // Remember the active language code so the "Restart required" text can go away if the language + // is changed and later reverted in the same session. Cannot use m_currentLanguage.code + // because m_currentLanguage holds the effective language: if the language code is "system", + // m_currentLanguage will hold "en-us" for example (whatever the system is set to). + QString activeLanguageCode = languageCode.val; + languageCode.ch.onReceive(this, [this, activeLanguageCode](const QString& newLanguageCode) { //! NOTE To change the language at the moment, a restart is required - m_needRestartToApplyLanguageChange = true; + m_needRestartToApplyLanguageChange = newLanguageCode != activeLanguageCode; m_needRestartToApplyLanguageChangeChanged.send(m_needRestartToApplyLanguageChange); }); diff --git a/src/framework/midi/imidiconfiguration.h b/src/framework/midi/imidiconfiguration.h index 4540699ac7b23..b49e9579a517b 100644 --- a/src/framework/midi/imidiconfiguration.h +++ b/src/framework/midi/imidiconfiguration.h @@ -41,6 +41,7 @@ class IMidiConfiguration : MODULE_EXPORT_INTERFACE virtual bool useRemoteControl() const = 0; virtual void setUseRemoteControl(bool value) = 0; + virtual async::Channel useRemoteControlChanged() const = 0; virtual MidiDeviceID midiInputDeviceId() const = 0; virtual void setMidiInputDeviceId(const MidiDeviceID& deviceId) = 0; @@ -52,6 +53,7 @@ class IMidiConfiguration : MODULE_EXPORT_INTERFACE virtual bool useMIDI20Output() const = 0; virtual void setUseMIDI20Output(bool use) = 0; + virtual async::Channel useMIDI20OutputChanged() const = 0; }; } diff --git a/src/framework/midi/internal/midiconfiguration.cpp b/src/framework/midi/internal/midiconfiguration.cpp index a09ee75835165..2cbf8f6f0ffb5 100644 --- a/src/framework/midi/internal/midiconfiguration.cpp +++ b/src/framework/midi/internal/midiconfiguration.cpp @@ -38,8 +38,11 @@ static const Settings::Key USE_MIDI20_OUTPUT_KEY(module_name, "io/midi/useMIDI20 void MidiConfiguration::init() { settings()->setDefaultValue(USE_REMOTE_CONTROL_KEY, Val(true)); + settings()->valueChanged(USE_REMOTE_CONTROL_KEY).onReceive(this, [this](const Val& val) { + m_useRemoteControlChanged.send(val.toBool()); + }); - settings()->setDefaultValue(MIDI_INPUT_DEVICE_ID, Val("")); + settings()->setDefaultValue(MIDI_INPUT_DEVICE_ID, Val(NONE_DEVICE_ID)); settings()->valueChanged(MIDI_INPUT_DEVICE_ID).onReceive(nullptr, [this](const Val&) { m_midiInputDeviceIdChanged.notify(); }); @@ -50,6 +53,9 @@ void MidiConfiguration::init() }); settings()->setDefaultValue(USE_MIDI20_OUTPUT_KEY, Val(true)); + settings()->valueChanged(USE_MIDI20_OUTPUT_KEY).onReceive(this, [this](const Val& val) { + m_useMIDI20OutputChanged.send(val.toBool()); + }); } bool MidiConfiguration::midiPortIsAvalaible() const @@ -67,6 +73,11 @@ void MidiConfiguration::setUseRemoteControl(bool value) settings()->setSharedValue(USE_REMOTE_CONTROL_KEY, Val(value)); } +async::Channel MidiConfiguration::useRemoteControlChanged() const +{ + return m_useRemoteControlChanged; +} + MidiDeviceID MidiConfiguration::midiInputDeviceId() const { return settings()->value(MIDI_INPUT_DEVICE_ID).toString(); @@ -106,3 +117,8 @@ void MidiConfiguration::setUseMIDI20Output(bool use) { settings()->setSharedValue(USE_MIDI20_OUTPUT_KEY, Val(use)); } + +async::Channel MidiConfiguration::useMIDI20OutputChanged() const +{ + return m_useMIDI20OutputChanged; +} diff --git a/src/framework/midi/internal/midiconfiguration.h b/src/framework/midi/internal/midiconfiguration.h index 43cc0badb0ad9..d556aef70ebf4 100644 --- a/src/framework/midi/internal/midiconfiguration.h +++ b/src/framework/midi/internal/midiconfiguration.h @@ -23,9 +23,10 @@ #define MUSE_MIDI_MIDICONFIGURATION_H #include "../imidiconfiguration.h" +#include "async/asyncable.h" namespace muse::midi { -class MidiConfiguration : public IMidiConfiguration +class MidiConfiguration : public IMidiConfiguration, public async::Asyncable { public: void init(); @@ -34,6 +35,7 @@ class MidiConfiguration : public IMidiConfiguration bool useRemoteControl() const override; void setUseRemoteControl(bool value) override; + async::Channel useRemoteControlChanged() const override; MidiDeviceID midiInputDeviceId() const override; void setMidiInputDeviceId(const MidiDeviceID& deviceId) override; @@ -45,10 +47,13 @@ class MidiConfiguration : public IMidiConfiguration bool useMIDI20Output() const override; void setUseMIDI20Output(bool use) override; + async::Channel useMIDI20OutputChanged() const override; private: async::Notification m_midiInputDeviceIdChanged; async::Notification m_midiOutputDeviceIdChanged; + async::Channel m_useRemoteControlChanged; + async::Channel m_useMIDI20OutputChanged; }; } diff --git a/src/framework/shortcuts/internal/shortcutsconfiguration.cpp b/src/framework/shortcuts/internal/shortcutsconfiguration.cpp index d20f564e1f713..34828fb40852e 100644 --- a/src/framework/shortcuts/internal/shortcutsconfiguration.cpp +++ b/src/framework/shortcuts/internal/shortcutsconfiguration.cpp @@ -40,6 +40,9 @@ void ShortcutsConfiguration::init() m_config = ConfigReader::read(":/configs/shortcuts.cfg"); settings()->setDefaultValue(ADVANCE_TO_NEXT_NOTE_ON_KEY_RELEASE, Val(true)); + settings()->valueChanged(ADVANCE_TO_NEXT_NOTE_ON_KEY_RELEASE).onReceive(this, [this](const Val& val) { + m_advanceToNextNoteOnKeyReleaseChanged.send(val.toBool()); + }); } QString ShortcutsConfiguration::currentKeyboardLayout() const @@ -83,3 +86,8 @@ void ShortcutsConfiguration::setAdvanceToNextNoteOnKeyRelease(bool value) { settings()->setSharedValue(ADVANCE_TO_NEXT_NOTE_ON_KEY_RELEASE, Val(value)); } + +muse::async::Channel ShortcutsConfiguration::advanceToNextNoteOnKeyReleaseChanged() const +{ + return m_advanceToNextNoteOnKeyReleaseChanged; +} diff --git a/src/framework/shortcuts/internal/shortcutsconfiguration.h b/src/framework/shortcuts/internal/shortcutsconfiguration.h index 00b426d406995..dfa2cf1478fb9 100644 --- a/src/framework/shortcuts/internal/shortcutsconfiguration.h +++ b/src/framework/shortcuts/internal/shortcutsconfiguration.h @@ -51,8 +51,11 @@ class ShortcutsConfiguration : public IShortcutsConfiguration, public Injectable bool advanceToNextNoteOnKeyRelease() const override; void setAdvanceToNextNoteOnKeyRelease(bool value) override; + virtual muse::async::Channel advanceToNextNoteOnKeyReleaseChanged() const override; private: Config m_config; + + muse::async::Channel m_advanceToNextNoteOnKeyReleaseChanged; }; } diff --git a/src/framework/shortcuts/ishortcutsconfiguration.h b/src/framework/shortcuts/ishortcutsconfiguration.h index a00e63fa80211..d7910667b22fc 100644 --- a/src/framework/shortcuts/ishortcutsconfiguration.h +++ b/src/framework/shortcuts/ishortcutsconfiguration.h @@ -44,6 +44,7 @@ class IShortcutsConfiguration : MODULE_EXPORT_INTERFACE virtual bool advanceToNextNoteOnKeyRelease() const = 0; virtual void setAdvanceToNextNoteOnKeyRelease(bool value) = 0; + virtual muse::async::Channel advanceToNextNoteOnKeyReleaseChanged() const = 0; }; } diff --git a/src/framework/shortcuts/view/mididevicemappingmodel.cpp b/src/framework/shortcuts/view/mididevicemappingmodel.cpp index 6cec27a1c9069..4a9e6d405a13f 100644 --- a/src/framework/shortcuts/view/mididevicemappingmodel.cpp +++ b/src/framework/shortcuts/view/mididevicemappingmodel.cpp @@ -124,6 +124,10 @@ QHash MidiDeviceMappingModel::roleNames() const void MidiDeviceMappingModel::load() { + midiConfiguration()->useRemoteControlChanged().onReceive(this, [this](bool val) { + emit useRemoteControlChanged(val); + }); + beginResetModel(); m_midiMappings.clear(); diff --git a/src/framework/stubs/midi/midiconfigurationstub.cpp b/src/framework/stubs/midi/midiconfigurationstub.cpp index e9205e3698eb0..7fb1608499106 100644 --- a/src/framework/stubs/midi/midiconfigurationstub.cpp +++ b/src/framework/stubs/midi/midiconfigurationstub.cpp @@ -38,6 +38,12 @@ void MidiConfigurationStub::setUseRemoteControl(bool) { } +async::Channel MidiConfigurationStub::useRemoteControlChanged() const +{ + static async::Channel ch; + return ch; +} + MidiDeviceID MidiConfigurationStub::midiInputDeviceId() const { return MidiDeviceID(); @@ -49,8 +55,8 @@ void MidiConfigurationStub::setMidiInputDeviceId(const MidiDeviceID&) async::Notification MidiConfigurationStub::midiInputDeviceIdChanged() const { - static async::Notification n; - return n; + static async::Notification ch; + return ch; } MidiDeviceID MidiConfigurationStub::midiOutputDeviceId() const @@ -76,3 +82,9 @@ bool MidiConfigurationStub::useMIDI20Output() const void MidiConfigurationStub::setUseMIDI20Output(bool) { } + +async::Channel MidiConfigurationStub::useMIDI20OutputChanged() const +{ + static async::Channel n; + return n; +} diff --git a/src/framework/stubs/midi/midiconfigurationstub.h b/src/framework/stubs/midi/midiconfigurationstub.h index 1df8898cb077a..277f8e120c239 100644 --- a/src/framework/stubs/midi/midiconfigurationstub.h +++ b/src/framework/stubs/midi/midiconfigurationstub.h @@ -34,6 +34,7 @@ class MidiConfigurationStub : public IMidiConfiguration bool useRemoteControl() const override; void setUseRemoteControl(bool value) override; + async::Channel useRemoteControlChanged() const override; MidiDeviceID midiInputDeviceId() const override; void setMidiInputDeviceId(const MidiDeviceID& deviceId) override; @@ -45,6 +46,7 @@ class MidiConfigurationStub : public IMidiConfiguration bool useMIDI20Output() const override; void setUseMIDI20Output(bool use) override; + async::Channel useMIDI20OutputChanged() const override; }; } diff --git a/src/framework/stubs/shortcuts/shortcutsconfigurationstub.cpp b/src/framework/stubs/shortcuts/shortcutsconfigurationstub.cpp index 5e6a925d496f9..18e5e2a4abbad 100644 --- a/src/framework/stubs/shortcuts/shortcutsconfigurationstub.cpp +++ b/src/framework/stubs/shortcuts/shortcutsconfigurationstub.cpp @@ -56,3 +56,9 @@ bool ShortcutsConfigurationStub::advanceToNextNoteOnKeyRelease() const void ShortcutsConfigurationStub::setAdvanceToNextNoteOnKeyRelease(bool) { } + +async::Channel ShortcutsConfigurationStub::advanceToNextNoteOnKeyReleaseChanged() const +{ + static async::Channel ch; + return ch; +} diff --git a/src/framework/stubs/shortcuts/shortcutsconfigurationstub.h b/src/framework/stubs/shortcuts/shortcutsconfigurationstub.h index 4265273d000ef..9957b56a33d2a 100644 --- a/src/framework/stubs/shortcuts/shortcutsconfigurationstub.h +++ b/src/framework/stubs/shortcuts/shortcutsconfigurationstub.h @@ -38,6 +38,7 @@ class ShortcutsConfigurationStub : public IShortcutsConfiguration bool advanceToNextNoteOnKeyRelease() const override; void setAdvanceToNextNoteOnKeyRelease(bool value) override; + muse::async::Channel advanceToNextNoteOnKeyReleaseChanged() const override; }; } diff --git a/src/framework/stubs/update/updateconfigurationstub.cpp b/src/framework/stubs/update/updateconfigurationstub.cpp index 9987695b650e2..deea190254af5 100644 --- a/src/framework/stubs/update/updateconfigurationstub.cpp +++ b/src/framework/stubs/update/updateconfigurationstub.cpp @@ -46,6 +46,12 @@ void UpdateConfigurationStub::setNeedCheckForUpdate(bool) { } +muse::async::Notification UpdateConfigurationStub::needCheckForUpdateChanged() const +{ + static muse::async::Notification n; + return n; +} + std::string UpdateConfigurationStub::skippedReleaseVersion() const { return ""; diff --git a/src/framework/stubs/update/updateconfigurationstub.h b/src/framework/stubs/update/updateconfigurationstub.h index 712e15a82db53..86a77ff721bc1 100644 --- a/src/framework/stubs/update/updateconfigurationstub.h +++ b/src/framework/stubs/update/updateconfigurationstub.h @@ -35,6 +35,7 @@ class UpdateConfigurationStub : public IUpdateConfiguration bool needCheckForUpdate() const override; void setNeedCheckForUpdate(bool needCheck) override; + muse::async::Notification needCheckForUpdateChanged() const override; std::string skippedReleaseVersion() const override; void setSkippedReleaseVersion(const std::string& version) override; diff --git a/src/framework/update/internal/updateconfiguration.cpp b/src/framework/update/internal/updateconfiguration.cpp index 96100aaf27d55..4d05376d86210 100644 --- a/src/framework/update/internal/updateconfiguration.cpp +++ b/src/framework/update/internal/updateconfiguration.cpp @@ -64,6 +64,9 @@ void UpdateConfiguration::init() m_config = ConfigReader::read(":/configs/update.cfg"); settings()->setDefaultValue(CHECK_FOR_UPDATE_KEY, Val(isAppUpdatable())); + settings()->valueChanged(CHECK_FOR_UPDATE_KEY).onReceive(this, [this](const Val&) { + m_needCheckForUpdateChanged.notify(); + }); bool allowUpdateOnPreRelease = false; #ifdef MUSESCORE_ALLOW_UPDATE_ON_PRERELEASE @@ -99,6 +102,11 @@ void UpdateConfiguration::setNeedCheckForUpdate(bool needCheck) settings()->setSharedValue(CHECK_FOR_UPDATE_KEY, Val(needCheck)); } +async::Notification UpdateConfiguration::needCheckForUpdateChanged() const +{ + return m_needCheckForUpdateChanged; +} + std::string UpdateConfiguration::skippedReleaseVersion() const { return settings()->value(SKIPPED_VERSION_KEY).toString(); diff --git a/src/framework/update/internal/updateconfiguration.h b/src/framework/update/internal/updateconfiguration.h index ad05f4c8e31f4..35a51639047cf 100644 --- a/src/framework/update/internal/updateconfiguration.h +++ b/src/framework/update/internal/updateconfiguration.h @@ -48,6 +48,7 @@ class UpdateConfiguration : public IUpdateConfiguration, public Injectable, publ bool needCheckForUpdate() const override; void setNeedCheckForUpdate(bool needCheck) override; + muse::async::Notification needCheckForUpdateChanged() const override; std::string skippedReleaseVersion() const override; void setSkippedReleaseVersion(const std::string& version) override; @@ -68,6 +69,7 @@ class UpdateConfiguration : public IUpdateConfiguration, public Injectable, publ muse::io::path_t updateRequestHistoryJsonPath() const override; private: + muse::async::Notification m_needCheckForUpdateChanged; Config m_config; }; diff --git a/src/framework/update/iupdateconfiguration.h b/src/framework/update/iupdateconfiguration.h index 92f8b3f947e77..af23d7b261da5 100644 --- a/src/framework/update/iupdateconfiguration.h +++ b/src/framework/update/iupdateconfiguration.h @@ -22,6 +22,7 @@ #ifndef MUSE_UPDATE_IUPDATECONFIGURATION_H #define MUSE_UPDATE_IUPDATECONFIGURATION_H +#include "async/notification.h" #include "io/path.h" #include "network/networktypes.h" @@ -42,6 +43,7 @@ class IUpdateConfiguration : MODULE_EXPORT_INTERFACE virtual bool needCheckForUpdate() const = 0; virtual void setNeedCheckForUpdate(bool needCheck) = 0; + virtual muse::async::Notification needCheckForUpdateChanged() const = 0; virtual std::string skippedReleaseVersion() const = 0; virtual void setSkippedReleaseVersion(const std::string& version) = 0; diff --git a/src/framework/update/tests/mocks/updateconfigurationmock.h b/src/framework/update/tests/mocks/updateconfigurationmock.h index ce06853a1c13c..b8fa65eee8c56 100644 --- a/src/framework/update/tests/mocks/updateconfigurationmock.h +++ b/src/framework/update/tests/mocks/updateconfigurationmock.h @@ -37,6 +37,7 @@ class UpdateConfigurationMock : public IUpdateConfiguration MOCK_METHOD(bool, needCheckForUpdate, (), (const, override)); MOCK_METHOD(void, setNeedCheckForUpdate, (bool), (override)); + MOCK_METHOD(muse::async::Notification, needCheckForUpdateChanged, (), (const, override)); MOCK_METHOD(std::string, skippedReleaseVersion, (), (const, override)); MOCK_METHOD(void, setSkippedReleaseVersion, (const std::string&), (override)); diff --git a/src/importexport/mei/imeiconfiguration.h b/src/importexport/mei/imeiconfiguration.h index 82b81fa702dde..b110b689887ee 100644 --- a/src/importexport/mei/imeiconfiguration.h +++ b/src/importexport/mei/imeiconfiguration.h @@ -23,6 +23,7 @@ #define MU_IMPORTEXPORT_IMEICONFIGURATION_H #include "modularity/imoduleinterface.h" +#include "async/channel.h" namespace mu::iex::mei { class IMeiConfiguration : MODULE_EXPORT_INTERFACE @@ -34,6 +35,7 @@ class IMeiConfiguration : MODULE_EXPORT_INTERFACE virtual bool meiImportLayout() const = 0; virtual void setMeiImportLayout(bool value) = 0; + virtual muse::async::Channel meiImportLayoutChanged() const = 0; virtual bool meiExportLayout() const = 0; virtual void setMeiExportLayout(bool value) = 0; diff --git a/src/importexport/mei/internal/meiconfiguration.cpp b/src/importexport/mei/internal/meiconfiguration.cpp index f6ec8a7c10a04..94f644a708481 100644 --- a/src/importexport/mei/internal/meiconfiguration.cpp +++ b/src/importexport/mei/internal/meiconfiguration.cpp @@ -35,6 +35,10 @@ static const Settings::Key MEI_EXPORT_LAYOUT_KEY(module_name, "export/mei/export void MeiConfiguration::init() { settings()->setDefaultValue(MEI_IMPORT_LAYOUT_KEY, Val(true)); + settings()->valueChanged(MEI_IMPORT_LAYOUT_KEY).onReceive(this, [this](const Val& val) { + m_meiImportLayoutChanged.send(val.toBool()); + }); + settings()->setDefaultValue(MEI_EXPORT_LAYOUT_KEY, Val(true)); } @@ -48,6 +52,11 @@ void MeiConfiguration::setMeiImportLayout(bool value) settings()->setSharedValue(MEI_IMPORT_LAYOUT_KEY, Val(value)); } +async::Channel MeiConfiguration::meiImportLayoutChanged() const +{ + return m_meiImportLayoutChanged; +} + bool MeiConfiguration::meiExportLayout() const { return settings()->value(MEI_EXPORT_LAYOUT_KEY).toBool(); diff --git a/src/importexport/mei/internal/meiconfiguration.h b/src/importexport/mei/internal/meiconfiguration.h index ecda19989d380..05150fa10d9af 100644 --- a/src/importexport/mei/internal/meiconfiguration.h +++ b/src/importexport/mei/internal/meiconfiguration.h @@ -23,18 +23,23 @@ #define MU_IMPORTEXPORT_MEICONFIGURATION_H #include "../imeiconfiguration.h" +#include "async/asyncable.h" namespace mu::iex::mei { -class MeiConfiguration : public IMeiConfiguration +class MeiConfiguration : public IMeiConfiguration, public muse::async::Asyncable { public: void init(); bool meiImportLayout() const override; void setMeiImportLayout(bool value) override; + muse::async::Channel meiImportLayoutChanged() const override; bool meiExportLayout() const override; void setMeiExportLayout(bool value) override; + +private: + muse::async::Channel m_meiImportLayoutChanged; }; } diff --git a/src/importexport/midi/imidiconfiguration.h b/src/importexport/midi/imidiconfiguration.h index ee1572486baa7..3da00adea8823 100644 --- a/src/importexport/midi/imidiconfiguration.h +++ b/src/importexport/midi/imidiconfiguration.h @@ -25,6 +25,7 @@ #include #include "modularity/imoduleinterface.h" +#include "async/channel.h" #include "io/path.h" namespace mu::iex::midi { @@ -38,6 +39,7 @@ class IMidiImportExportConfiguration : MODULE_EXPORT_INTERFACE // import virtual int midiShortestNote() const = 0; //ticks virtual void setMidiShortestNote(int ticks) = 0; + virtual muse::async::Channel midiShortestNoteChanged() const = 0; virtual void setMidiImportOperationsFile(const std::optional& filePath) const = 0; diff --git a/src/importexport/midi/internal/midiconfiguration.cpp b/src/importexport/midi/internal/midiconfiguration.cpp index 425e2a2ca36ae..28628cdb5b5f5 100644 --- a/src/importexport/midi/internal/midiconfiguration.cpp +++ b/src/importexport/midi/internal/midiconfiguration.cpp @@ -38,6 +38,10 @@ static const Settings::Key EXPAND_REPEATS_KEY("iex_midi", "io/midi/expandRepeats void MidiConfiguration::init() { settings()->setDefaultValue(SHORTEST_NOTE_KEY, Val(mu::engraving::Constants::DIVISION / 4)); + settings()->valueChanged(SHORTEST_NOTE_KEY).onReceive(this, [this](const Val& val) { + m_midiShortestNoteChanged.send(val.toInt()); + }); + settings()->setDefaultValue(EXPAND_REPEATS_KEY, Val(true)); settings()->setDefaultValue(EXPORTRPNS_KEY, Val(true)); } @@ -52,6 +56,11 @@ void MidiConfiguration::setMidiShortestNote(int ticks) settings()->setSharedValue(SHORTEST_NOTE_KEY, Val(ticks)); } +async::Channel MidiConfiguration::midiShortestNoteChanged() const +{ + return m_midiShortestNoteChanged; +} + void MidiConfiguration::setMidiImportOperationsFile(const std::optional& filePath) const { if (filePath) { diff --git a/src/importexport/midi/internal/midiconfiguration.h b/src/importexport/midi/internal/midiconfiguration.h index 5cddbb75b38f3..43b6a0a0d99f6 100644 --- a/src/importexport/midi/internal/midiconfiguration.h +++ b/src/importexport/midi/internal/midiconfiguration.h @@ -22,11 +22,12 @@ #ifndef MU_IMPORTEXPORT_MIDICONFIGURATION_H #define MU_IMPORTEXPORT_MIDICONFIGURATION_H +#include "async/asyncable.h" #include "io/path.h" #include "../imidiconfiguration.h" namespace mu::iex::midi { -class MidiConfiguration : public IMidiImportExportConfiguration +class MidiConfiguration : public IMidiImportExportConfiguration, public muse::async::Asyncable { public: void init(); @@ -34,6 +35,7 @@ class MidiConfiguration : public IMidiImportExportConfiguration // import int midiShortestNote() const override; // ticks void setMidiShortestNote(int ticks) override; + muse::async::Channel midiShortestNoteChanged() const override; void setMidiImportOperationsFile(const std::optional& filePath) const override; @@ -43,6 +45,9 @@ class MidiConfiguration : public IMidiImportExportConfiguration bool isMidiExportRpns() const override; void setIsMidiExportRpns(bool exportRpns) override; + +private: + muse::async::Channel m_midiShortestNoteChanged; }; } diff --git a/src/importexport/musicxml/imusicxmlconfiguration.h b/src/importexport/musicxml/imusicxmlconfiguration.h index 048a6f3f08d67..8096ac0e48552 100644 --- a/src/importexport/musicxml/imusicxmlconfiguration.h +++ b/src/importexport/musicxml/imusicxmlconfiguration.h @@ -22,6 +22,7 @@ #pragma once #include "modularity/imoduleinterface.h" +#include "async/channel.h" #include "io/path.h" namespace mu::iex::musicxml { @@ -34,9 +35,11 @@ class IMusicXmlConfiguration : MODULE_EXPORT_INTERFACE virtual bool importBreaks() const = 0; virtual void setImportBreaks(bool value) = 0; + virtual muse::async::Channel importBreaksChanged() const = 0; virtual bool importLayout() const = 0; virtual void setImportLayout(bool value) = 0; + virtual muse::async::Channel importLayoutChanged() const = 0; virtual bool exportLayout() const = 0; virtual void setExportLayout(bool value) = 0; @@ -56,13 +59,16 @@ class IMusicXmlConfiguration : MODULE_EXPORT_INTERFACE virtual bool needUseDefaultFont() const = 0; virtual void setNeedUseDefaultFont(bool value) = 0; + virtual muse::async::Channel needUseDefaultFontChanged() const = 0; virtual void setNeedUseDefaultFontOverride(std::optional value) = 0; virtual bool needAskAboutApplyingNewStyle() const = 0; virtual void setNeedAskAboutApplyingNewStyle(bool value) = 0; + virtual muse::async::Channel needAskAboutApplyingNewStyleChanged() const = 0; virtual bool inferTextType() const = 0; virtual void setInferTextType(bool value) = 0; + virtual muse::async::Channel inferTextTypeChanged() const = 0; virtual void setInferTextTypeOverride(std::optional value) = 0; }; } diff --git a/src/importexport/musicxml/internal/musicxmlconfiguration.cpp b/src/importexport/musicxml/internal/musicxmlconfiguration.cpp index 06797ad015505..2c112692d1faf 100644 --- a/src/importexport/musicxml/internal/musicxmlconfiguration.cpp +++ b/src/importexport/musicxml/internal/musicxmlconfiguration.cpp @@ -43,7 +43,15 @@ static const Settings::Key MUSICXML_IMPORT_INFER_TEXT_TYPE(module_name, "import/ void MusicXmlConfiguration::init() { settings()->setDefaultValue(MUSICXML_IMPORT_BREAKS_KEY, Val(true)); + settings()->valueChanged(MUSICXML_IMPORT_BREAKS_KEY).onReceive(this, [this](const Val& val) { + m_importBreaksChanged.send(val.toBool()); + }); + settings()->setDefaultValue(MUSICXML_IMPORT_LAYOUT_KEY, Val(true)); + settings()->valueChanged(MUSICXML_IMPORT_LAYOUT_KEY).onReceive(this, [this](const Val& val) { + m_importLayoutChanged.send(val.toBool()); + }); + settings()->setDefaultValue(MUSICXML_EXPORT_LAYOUT_KEY, Val(true)); settings()->setDefaultValue(MUSICXML_EXPORT_MU3_COMPAT_KEY, Val(false)); settings()->setDescription(MUSICXML_EXPORT_MU3_COMPAT_KEY, @@ -56,9 +64,21 @@ void MusicXmlConfiguration::init() settings()->setDescription(MUSICXML_EXPORT_INVISIBLE_ELEMENTS_KEY, muse::trc("iex_musicxml", "Export invisible elements to MusicXML")); settings()->setCanBeManuallyEdited(MUSICXML_EXPORT_INVISIBLE_ELEMENTS_KEY, true); + settings()->setDefaultValue(MIGRATION_APPLY_EDWIN_FOR_XML, Val(false)); + settings()->valueChanged(MIGRATION_APPLY_EDWIN_FOR_XML).onReceive(this, [this](const Val& val) { + m_needUseDefaultFontChanged.send(val.toBool()); + }); + settings()->setDefaultValue(MIGRATION_NOT_ASK_AGAIN_KEY, Val(false)); + settings()->valueChanged(MIGRATION_NOT_ASK_AGAIN_KEY).onReceive(this, [this](const Val& val) { + m_needAskAboutApplyingNewStyleChanged.send(val.toBool()); + }); + settings()->setDefaultValue(MUSICXML_IMPORT_INFER_TEXT_TYPE, Val(false)); + settings()->valueChanged(MUSICXML_IMPORT_INFER_TEXT_TYPE).onReceive(this, [this](const Val& val) { + m_inferTextTypeChanged.send(val.toBool()); + }); } bool MusicXmlConfiguration::importBreaks() const @@ -71,6 +91,11 @@ void MusicXmlConfiguration::setImportBreaks(bool value) settings()->setSharedValue(MUSICXML_IMPORT_BREAKS_KEY, Val(value)); } +async::Channel MusicXmlConfiguration::importBreaksChanged() const +{ + return m_importBreaksChanged; +} + bool MusicXmlConfiguration::importLayout() const { return settings()->value(MUSICXML_IMPORT_LAYOUT_KEY).toBool(); @@ -81,6 +106,11 @@ void MusicXmlConfiguration::setImportLayout(bool value) settings()->setSharedValue(MUSICXML_IMPORT_LAYOUT_KEY, Val(value)); } +async::Channel MusicXmlConfiguration::importLayoutChanged() const +{ + return m_importLayoutChanged; +} + bool MusicXmlConfiguration::exportLayout() const { return settings()->value(MUSICXML_EXPORT_LAYOUT_KEY).toBool(); @@ -135,6 +165,11 @@ void MusicXmlConfiguration::setNeedUseDefaultFont(bool value) settings()->setSharedValue(MIGRATION_APPLY_EDWIN_FOR_XML, Val(value)); } +async::Channel MusicXmlConfiguration::needUseDefaultFontChanged() const +{ + return m_needUseDefaultFontChanged; +} + void MusicXmlConfiguration::setNeedUseDefaultFontOverride(std::optional value) { m_needUseDefaultFontOverride = value; @@ -150,6 +185,11 @@ void MusicXmlConfiguration::setNeedAskAboutApplyingNewStyle(bool value) settings()->setSharedValue(MIGRATION_NOT_ASK_AGAIN_KEY, Val(!value)); } +async::Channel MusicXmlConfiguration::needAskAboutApplyingNewStyleChanged() const +{ + return m_needAskAboutApplyingNewStyleChanged; +} + bool MusicXmlConfiguration::inferTextType() const { if (m_inferTextTypeOverride.has_value()) { @@ -164,6 +204,11 @@ void MusicXmlConfiguration::setInferTextType(bool value) settings()->setSharedValue(MUSICXML_IMPORT_INFER_TEXT_TYPE, Val(value)); } +async::Channel MusicXmlConfiguration::inferTextTypeChanged() const +{ + return m_inferTextTypeChanged; +} + void MusicXmlConfiguration::setInferTextTypeOverride(std::optional value) { m_inferTextTypeOverride = value; diff --git a/src/importexport/musicxml/internal/musicxmlconfiguration.h b/src/importexport/musicxml/internal/musicxmlconfiguration.h index 67b976e8a2fc9..3ddc414ace175 100644 --- a/src/importexport/musicxml/internal/musicxmlconfiguration.h +++ b/src/importexport/musicxml/internal/musicxmlconfiguration.h @@ -22,18 +22,21 @@ #pragma once #include "../imusicxmlconfiguration.h" +#include "async/asyncable.h" namespace mu::iex::musicxml { -class MusicXmlConfiguration : public IMusicXmlConfiguration +class MusicXmlConfiguration : public IMusicXmlConfiguration, public muse::async::Asyncable { public: void init(); bool importBreaks() const override; void setImportBreaks(bool value) override; + muse::async::Channel importBreaksChanged() const override; bool importLayout() const override; void setImportLayout(bool value) override; + muse::async::Channel importLayoutChanged() const override; bool exportLayout() const override; void setExportLayout(bool value) override; @@ -49,17 +52,26 @@ class MusicXmlConfiguration : public IMusicXmlConfiguration bool needUseDefaultFont() const override; void setNeedUseDefaultFont(bool value) override; + muse::async::Channel needUseDefaultFontChanged() const override; void setNeedUseDefaultFontOverride(std::optional value) override; bool needAskAboutApplyingNewStyle() const override; void setNeedAskAboutApplyingNewStyle(bool value) override; + muse::async::Channel needAskAboutApplyingNewStyleChanged() const override; bool inferTextType() const override; void setInferTextType(bool value) override; + muse::async::Channel inferTextTypeChanged() const override; void setInferTextTypeOverride(std::optional value) override; private: std::optional m_needUseDefaultFontOverride; std::optional m_inferTextTypeOverride; + + muse::async::Channel m_importBreaksChanged; + muse::async::Channel m_importLayoutChanged; + muse::async::Channel m_needUseDefaultFontChanged; + muse::async::Channel m_needAskAboutApplyingNewStyleChanged; + muse::async::Channel m_inferTextTypeChanged; }; } diff --git a/src/importexport/ove/internal/oveconfiguration.cpp b/src/importexport/ove/internal/oveconfiguration.cpp index 29049fa3db90e..cef89e99fb7a3 100644 --- a/src/importexport/ove/internal/oveconfiguration.cpp +++ b/src/importexport/ove/internal/oveconfiguration.cpp @@ -32,6 +32,9 @@ static const Settings::Key IMPORT_OVERTURE_CHARSET_KEY("iex_ove", "import/overtu void OveConfiguration::init() { settings()->setDefaultValue(IMPORT_OVERTURE_CHARSET_KEY, Val("GBK")); + settings()->valueChanged(IMPORT_OVERTURE_CHARSET_KEY).onReceive(this, [this](const Val& val) { + m_importOvertureCharsetChanged.send(val.toString()); + }); } std::string OveConfiguration::importOvertureCharset() const @@ -43,3 +46,8 @@ void OveConfiguration::setImportOvertureCharset(const std::string& charset) { settings()->setSharedValue(IMPORT_OVERTURE_CHARSET_KEY, Val(charset)); } + +async::Channel OveConfiguration::importOvertureCharsetChanged() const +{ + return m_importOvertureCharsetChanged; +} diff --git a/src/importexport/ove/internal/oveconfiguration.h b/src/importexport/ove/internal/oveconfiguration.h index 178dbbec0b658..e580bfb88af51 100644 --- a/src/importexport/ove/internal/oveconfiguration.h +++ b/src/importexport/ove/internal/oveconfiguration.h @@ -23,15 +23,20 @@ #define MU_IMPORTEXPORT_OVECONFIGURATION_H #include "../ioveconfiguration.h" +#include "async/asyncable.h" namespace mu::iex::ove { -class OveConfiguration : public IOveConfiguration +class OveConfiguration : public IOveConfiguration, public muse::async::Asyncable { public: void init(); std::string importOvertureCharset() const override; void setImportOvertureCharset(const std::string& charset) override; + muse::async::Channel importOvertureCharsetChanged() const override; + +private: + muse::async::Channel m_importOvertureCharsetChanged; }; } diff --git a/src/importexport/ove/ioveconfiguration.h b/src/importexport/ove/ioveconfiguration.h index 8dc6cb795da46..cc06f254d1d75 100644 --- a/src/importexport/ove/ioveconfiguration.h +++ b/src/importexport/ove/ioveconfiguration.h @@ -24,6 +24,7 @@ #include +#include "async/channel.h" #include "modularity/imoduleinterface.h" namespace mu::iex::ove { @@ -36,6 +37,7 @@ class IOveConfiguration : MODULE_EXPORT_INTERFACE virtual std::string importOvertureCharset() const = 0; virtual void setImportOvertureCharset(const std::string& charset) = 0; + virtual muse::async::Channel importOvertureCharsetChanged() const = 0; }; } diff --git a/src/notation/inotationconfiguration.h b/src/notation/inotationconfiguration.h index 9a65b6a90575f..aac4559873c1c 100644 --- a/src/notation/inotationconfiguration.h +++ b/src/notation/inotationconfiguration.h @@ -86,6 +86,7 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual int selectionProximity() const = 0; virtual void setSelectionProximity(int proximity) = 0; + virtual muse::async::Channel selectionProximityChanged() const = 0; virtual ZoomType defaultZoomType() const = 0; virtual void setDefaultZoomType(ZoomType zoomType) = 0; @@ -93,6 +94,8 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual int defaultZoom() const = 0; virtual void setDefaultZoom(int zoomPercentage) = 0; + virtual muse::async::Notification defaultZoomChanged() const = 0; + virtual QList possibleZoomPercentageList() const = 0; virtual qreal scalingFromZoomPercentage(int zoomPercentage) const = 0; @@ -100,6 +103,7 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual int mouseZoomPrecision() const = 0; virtual void setMouseZoomPrecision(int precision) = 0; + virtual muse::async::Notification mouseZoomPrecisionChanged() const = 0; virtual std::string fontFamily() const = 0; virtual int fontSize() const = 0; @@ -110,9 +114,11 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual muse::io::path_t defaultStyleFilePath() const = 0; virtual void setDefaultStyleFilePath(const muse::io::path_t& path) = 0; + virtual muse::async::Channel defaultStyleFilePathChanged() const = 0; virtual muse::io::path_t partStyleFilePath() const = 0; virtual void setPartStyleFilePath(const muse::io::path_t& path) = 0; + virtual muse::async::Channel partStyleFilePathChanged() const = 0; virtual bool isMidiInputEnabled() const = 0; virtual void setIsMidiInputEnabled(bool enabled) = 0; @@ -149,15 +155,19 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual bool colorNotesOutsideOfUsablePitchRange() const = 0; virtual void setColorNotesOutsideOfUsablePitchRange(bool value) = 0; + virtual muse::async::Channel colorNotesOutsideOfUsablePitchRangeChanged() const = 0; virtual bool warnGuitarBends() const = 0; virtual void setWarnGuitarBends(bool value) = 0; + virtual muse::async::Channel warnGuitarBendsChanged() const = 0; virtual int delayBetweenNotesInRealTimeModeMilliseconds() const = 0; virtual void setDelayBetweenNotesInRealTimeModeMilliseconds(int delayMs) = 0; + virtual muse::async::Channel delayBetweenNotesInRealTimeModeMillisecondsChanged() const = 0; virtual int notePlayDurationMilliseconds() const = 0; virtual void setNotePlayDurationMilliseconds(int durationMs) = 0; + virtual muse::async::Channel notePlayDurationMillisecondsChanged() const = 0; virtual void setTemplateModeEnabled(std::optional enabled) = 0; virtual void setTestModeEnabled(std::optional enabled) = 0; @@ -205,6 +215,7 @@ class INotationConfiguration : MODULE_EXPORT_INTERFACE virtual muse::io::path_t styleFileImportPath() const = 0; virtual void setStyleFileImportPath(const muse::io::path_t& path) = 0; + virtual muse::async::Channel styleFileImportPathChanged() const = 0; virtual int styleDialogLastPageIndex() const = 0; virtual void setStyleDialogLastPageIndex(int value) = 0; diff --git a/src/notation/internal/notationconfiguration.cpp b/src/notation/internal/notationconfiguration.cpp index ce7a59827f425..afc7ef27f2761 100644 --- a/src/notation/internal/notationconfiguration.cpp +++ b/src/notation/internal/notationconfiguration.cpp @@ -153,9 +153,18 @@ void NotationConfiguration::init() }); settings()->setDefaultValue(DEFAULT_ZOOM_TYPE, Val(ZoomType::Percentage)); + settings()->valueChanged(DEFAULT_ZOOM_TYPE).onReceive(this, [this](const Val&) { + m_defaultZoomChanged.notify(); + }); settings()->setDefaultValue(DEFAULT_ZOOM, Val(100)); + settings()->valueChanged(DEFAULT_ZOOM).onReceive(this, [this](const Val&) { + m_defaultZoomChanged.notify(); + }); settings()->setDefaultValue(KEYBOARD_ZOOM_PRECISION, Val(2)); settings()->setDefaultValue(MOUSE_ZOOM_PRECISION, Val(6)); + settings()->valueChanged(MOUSE_ZOOM_PRECISION).onReceive(this, [this](const Val&) { + m_mouseZoomPrecisionChanged.notify(); + }); settings()->setDefaultValue(USER_STYLES_PATH, Val(globalConfiguration()->userDataPath() + "/Styles")); settings()->valueChanged(USER_STYLES_PATH).onReceive(nullptr, [this](const Val& val) { @@ -167,6 +176,9 @@ void NotationConfiguration::init() } settings()->setDefaultValue(SELECTION_PROXIMITY, Val(2)); + settings()->valueChanged(SELECTION_PROXIMITY).onReceive(this, [this](const Val& val) { + m_selectionProximityChanged.send(val.toInt()); + }); settings()->setDefaultValue(IS_MIDI_INPUT_ENABLED, Val(true)); settings()->setDefaultValue(IS_AUTOMATICALLY_PAN_ENABLED, Val(true)); settings()->setDefaultValue(IS_PLAY_REPEATS_ENABLED, Val(true)); @@ -193,9 +205,25 @@ void NotationConfiguration::init() }); settings()->setDefaultValue(COLOR_NOTES_OUTSIDE_OF_USABLE_PITCH_RANGE, Val(true)); + settings()->valueChanged(COLOR_NOTES_OUTSIDE_OF_USABLE_PITCH_RANGE).onReceive(this, [this](const Val& val) { + m_colorNotesOutsideOfUsablePitchRangeChanged.send(val.toBool()); + }); settings()->setDefaultValue(WARN_GUITAR_BENDS, Val(true)); + settings()->valueChanged(WARN_GUITAR_BENDS).onReceive(this, [this](const Val& val) { + m_warnGuitarBendsChanged.send(val.toBool()); + }); settings()->setDefaultValue(REALTIME_DELAY, Val(750)); + settings()->valueChanged(REALTIME_DELAY).onReceive(this, [this](const Val& val) { + m_delayBetweenNotesInRealTimeModeMillisecondsChanged.send(val.toInt()); + }); settings()->setDefaultValue(NOTE_DEFAULT_PLAY_DURATION, Val(500)); + settings()->valueChanged(NOTE_DEFAULT_PLAY_DURATION).onReceive(this, [this](const Val& val) { + m_notePlayDurationMillisecondsChanged.send(val.toInt()); + }); + + settings()->valueChanged(STYLE_FILE_IMPORT_PATH_KEY).onReceive(this, [this](const Val& val) { + m_styleFileImportPathChanged.send(val.toString()); + }); settings()->setDefaultValue(FIRST_SCORE_ORDER_LIST_KEY, Val(globalConfiguration()->appDataPath().toStdString() + "instruments/orders.xml")); @@ -484,6 +512,11 @@ void NotationConfiguration::setSelectionProximity(int proximity) settings()->setSharedValue(SELECTION_PROXIMITY, Val(proximity)); } +Channel NotationConfiguration::selectionProximityChanged() const +{ + return m_selectionProximityChanged; +} + ZoomType NotationConfiguration::defaultZoomType() const { return settings()->value(DEFAULT_ZOOM_TYPE).toEnum(); @@ -504,6 +537,11 @@ void NotationConfiguration::setDefaultZoom(int zoomPercentage) settings()->setSharedValue(DEFAULT_ZOOM, Val(zoomPercentage)); } +Notification NotationConfiguration::defaultZoomChanged() const +{ + return m_defaultZoomChanged; +} + qreal NotationConfiguration::scalingFromZoomPercentage(int zoomPercentage) const { return zoomPercentage / 100.0 * notationScaling(); @@ -531,6 +569,11 @@ void NotationConfiguration::setMouseZoomPrecision(int precision) settings()->setSharedValue(MOUSE_ZOOM_PRECISION, Val(precision)); } +muse::async::Notification NotationConfiguration::mouseZoomPrecisionChanged() const +{ + return m_mouseZoomPrecisionChanged; +} + std::string NotationConfiguration::fontFamily() const { return uiConfiguration()->fontFamily(); @@ -566,6 +609,11 @@ void NotationConfiguration::setDefaultStyleFilePath(const muse::io::path_t& path engravingConfiguration()->setDefaultStyleFilePath(path.toQString()); } +async::Channel NotationConfiguration::defaultStyleFilePathChanged() const +{ + return engravingConfiguration()->defaultStyleFilePathChanged(); +} + muse::io::path_t NotationConfiguration::partStyleFilePath() const { return engravingConfiguration()->partStyleFilePath(); @@ -576,6 +624,11 @@ void NotationConfiguration::setPartStyleFilePath(const muse::io::path_t& path) engravingConfiguration()->setPartStyleFilePath(path.toQString()); } +async::Channel NotationConfiguration::partStyleFilePathChanged() const +{ + return engravingConfiguration()->partStyleFilePathChanged(); +} + bool NotationConfiguration::isMidiInputEnabled() const { return settings()->value(IS_MIDI_INPUT_ENABLED).toBool(); @@ -711,6 +764,11 @@ void NotationConfiguration::setColorNotesOutsideOfUsablePitchRange(bool value) settings()->setSharedValue(COLOR_NOTES_OUTSIDE_OF_USABLE_PITCH_RANGE, Val(value)); } +async::Channel NotationConfiguration::colorNotesOutsideOfUsablePitchRangeChanged() const +{ + return m_colorNotesOutsideOfUsablePitchRangeChanged; +} + bool NotationConfiguration::warnGuitarBends() const { return settings()->value(WARN_GUITAR_BENDS).toBool(); @@ -722,6 +780,11 @@ void NotationConfiguration::setWarnGuitarBends(bool value) settings()->setSharedValue(WARN_GUITAR_BENDS, Val(value)); } +async::Channel NotationConfiguration::warnGuitarBendsChanged() const +{ + return m_warnGuitarBendsChanged; +} + int NotationConfiguration::delayBetweenNotesInRealTimeModeMilliseconds() const { return settings()->value(REALTIME_DELAY).toInt(); @@ -732,6 +795,11 @@ void NotationConfiguration::setDelayBetweenNotesInRealTimeModeMilliseconds(int d settings()->setSharedValue(REALTIME_DELAY, Val(delayMs)); } +async::Channel NotationConfiguration::delayBetweenNotesInRealTimeModeMillisecondsChanged() const +{ + return m_delayBetweenNotesInRealTimeModeMillisecondsChanged; +} + int NotationConfiguration::notePlayDurationMilliseconds() const { return settings()->value(NOTE_DEFAULT_PLAY_DURATION).toInt(); @@ -743,6 +811,11 @@ void NotationConfiguration::setNotePlayDurationMilliseconds(int durationMs) settings()->setSharedValue(NOTE_DEFAULT_PLAY_DURATION, Val(durationMs)); } +async::Channel NotationConfiguration::notePlayDurationMillisecondsChanged() const +{ + return m_notePlayDurationMillisecondsChanged; +} + void NotationConfiguration::setTemplateModeEnabled(std::optional enabled) { mu::engraving::MScore::saveTemplateMode = enabled ? enabled.value() : false; @@ -966,6 +1039,11 @@ void NotationConfiguration::setStyleFileImportPath(const muse::io::path_t& path) settings()->setSharedValue(STYLE_FILE_IMPORT_PATH_KEY, Val(path.toStdString())); } +async::Channel NotationConfiguration::styleFileImportPathChanged() const +{ + return m_styleFileImportPathChanged; +} + int NotationConfiguration::styleDialogLastPageIndex() const { return m_styleDialogLastPageIndex; diff --git a/src/notation/internal/notationconfiguration.h b/src/notation/internal/notationconfiguration.h index 134b9682330f3..3a8d0b3fd2ef6 100644 --- a/src/notation/internal/notationconfiguration.h +++ b/src/notation/internal/notationconfiguration.h @@ -91,6 +91,7 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: int selectionProximity() const override; void setSelectionProximity(int proximity) override; + muse::async::Channel selectionProximityChanged() const override; ZoomType defaultZoomType() const override; void setDefaultZoomType(ZoomType zoomType) override; @@ -98,6 +99,8 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: int defaultZoom() const override; void setDefaultZoom(int zoomPercentage) override; + muse::async::Notification defaultZoomChanged() const override; + qreal scalingFromZoomPercentage(int zoomPercentage) const override; int zoomPercentageFromScaling(qreal scaling) const override; @@ -105,6 +108,7 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: int mouseZoomPrecision() const override; void setMouseZoomPrecision(int precision) override; + muse::async::Notification mouseZoomPrecisionChanged() const override; std::string fontFamily() const override; int fontSize() const override; @@ -115,9 +119,11 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: muse::io::path_t defaultStyleFilePath() const override; void setDefaultStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel defaultStyleFilePathChanged() const override; muse::io::path_t partStyleFilePath() const override; void setPartStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel partStyleFilePathChanged() const override; bool isMidiInputEnabled() const override; void setIsMidiInputEnabled(bool enabled) override; @@ -154,15 +160,19 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: bool colorNotesOutsideOfUsablePitchRange() const override; void setColorNotesOutsideOfUsablePitchRange(bool value) override; + muse::async::Channel colorNotesOutsideOfUsablePitchRangeChanged() const override; bool warnGuitarBends() const override; void setWarnGuitarBends(bool value) override; + muse::async::Channel warnGuitarBendsChanged() const override; int delayBetweenNotesInRealTimeModeMilliseconds() const override; void setDelayBetweenNotesInRealTimeModeMilliseconds(int delayMs) override; + muse::async::Channel delayBetweenNotesInRealTimeModeMillisecondsChanged() const override; int notePlayDurationMilliseconds() const override; void setNotePlayDurationMilliseconds(int durationMs) override; + muse::async::Channel notePlayDurationMillisecondsChanged() const override; void setTemplateModeEnabled(std::optional enabled) override; void setTestModeEnabled(std::optional enabled) override; @@ -209,6 +219,7 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: muse::io::path_t styleFileImportPath() const override; void setStyleFileImportPath(const muse::io::path_t& path) override; + muse::async::Channel styleFileImportPathChanged() const override; int styleDialogLastPageIndex() const override; void setStyleDialogLastPageIndex(int value) override; @@ -227,10 +238,18 @@ class NotationConfiguration : public INotationConfiguration, public muse::async: muse::async::Notification m_backgroundChanged; muse::async::Notification m_foregroundChanged; + muse::async::Notification m_defaultZoomChanged; + muse::async::Notification m_mouseZoomPrecisionChanged; muse::async::Channel m_canvasOrientationChanged; muse::async::Channel m_userStylesPathChanged; muse::async::Notification m_scoreOrderListPathsChanged; muse::async::Notification m_isLimitCanvasScrollAreaChanged; + muse::async::Channel m_selectionProximityChanged; + muse::async::Channel m_colorNotesOutsideOfUsablePitchRangeChanged; + muse::async::Channel m_warnGuitarBendsChanged; + muse::async::Channel m_delayBetweenNotesInRealTimeModeMillisecondsChanged; + muse::async::Channel m_notePlayDurationMillisecondsChanged; + muse::async::Channel m_styleFileImportPathChanged; muse::async::Notification m_isPlayRepeatsChanged; muse::async::Notification m_isPlayChordSymbolsChanged; muse::ValCh m_pianoKeyboardNumberOfKeys; diff --git a/src/notation/tests/mocks/notationconfigurationmock.h b/src/notation/tests/mocks/notationconfigurationmock.h index 0fd1e9ce850df..bbb048e323131 100644 --- a/src/notation/tests/mocks/notationconfigurationmock.h +++ b/src/notation/tests/mocks/notationconfigurationmock.h @@ -76,6 +76,7 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(int, selectionProximity, (), (const, override)); MOCK_METHOD(void, setSelectionProximity, (int), (override)); + MOCK_METHOD(muse::async::Channel, selectionProximityChanged, (), (const, override)); MOCK_METHOD(ZoomType, defaultZoomType, (), (const, override)); MOCK_METHOD(void, setDefaultZoomType, (ZoomType), (override)); @@ -83,6 +84,8 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(int, defaultZoom, (), (const, override)); MOCK_METHOD(void, setDefaultZoom, (int), (override)); + MOCK_METHOD(muse::async::Notification, defaultZoomChanged, (), (const, override)); + MOCK_METHOD(QList, possibleZoomPercentageList, (), (const, override)); MOCK_METHOD(qreal, scalingFromZoomPercentage, (int), (const, override)); @@ -90,6 +93,7 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(int, mouseZoomPrecision, (), (const, override)); MOCK_METHOD(void, setMouseZoomPrecision, (int), (override)); + MOCK_METHOD(muse::async::Notification, mouseZoomPrecisionChanged, (), (const, override)); MOCK_METHOD(std::string, fontFamily, (), (const, override)); MOCK_METHOD(int, fontSize, (), (const, override)); @@ -100,9 +104,11 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(muse::io::path_t, defaultStyleFilePath, (), (const, override)); MOCK_METHOD(void, setDefaultStyleFilePath, (const muse::io::path_t&), (override)); + MOCK_METHOD(muse::async::Channel, defaultStyleFilePathChanged, (), (const, override)); MOCK_METHOD(muse::io::path_t, partStyleFilePath, (), (const, override)); MOCK_METHOD(void, setPartStyleFilePath, (const muse::io::path_t&), (override)); + MOCK_METHOD(muse::async::Channel, partStyleFilePathChanged, (), (const, override)); MOCK_METHOD(bool, isMidiInputEnabled, (), (const, override)); MOCK_METHOD(void, setIsMidiInputEnabled, (bool), (override)); @@ -139,15 +145,19 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(bool, colorNotesOutsideOfUsablePitchRange, (), (const, override)); MOCK_METHOD(void, setColorNotesOutsideOfUsablePitchRange, (bool), (override)); + MOCK_METHOD((muse::async::Channel), colorNotesOutsideOfUsablePitchRangeChanged, (), (const, override)); MOCK_METHOD(bool, warnGuitarBends, (), (const, override)); MOCK_METHOD(void, setWarnGuitarBends, (bool), (override)); + MOCK_METHOD((muse::async::Channel), warnGuitarBendsChanged, (), (const, override)); MOCK_METHOD(int, delayBetweenNotesInRealTimeModeMilliseconds, (), (const, override)); MOCK_METHOD(void, setDelayBetweenNotesInRealTimeModeMilliseconds, (int), (override)); + MOCK_METHOD((muse::async::Channel), delayBetweenNotesInRealTimeModeMillisecondsChanged, (), (const, override)); MOCK_METHOD(int, notePlayDurationMilliseconds, (), (const, override)); MOCK_METHOD(void, setNotePlayDurationMilliseconds, (int), (override)); + MOCK_METHOD((muse::async::Channel), notePlayDurationMillisecondsChanged, (), (const, override)); MOCK_METHOD(void, setTemplateModeEnabled, (std::optional), (override)); MOCK_METHOD(void, setTestModeEnabled, (std::optional), (override)); @@ -194,6 +204,7 @@ class NotationConfigurationMock : public INotationConfiguration MOCK_METHOD(muse::io::path_t, styleFileImportPath, (), (const, override)); MOCK_METHOD(void, setStyleFileImportPath, (const muse::io::path_t&), (override)); + MOCK_METHOD((muse::async::Channel), styleFileImportPathChanged, (), (const, override)); MOCK_METHOD(int, styleDialogLastPageIndex, (), (const, override)); MOCK_METHOD(void, setStyleDialogLastPageIndex, (int), (override)); diff --git a/src/playback/internal/playbackconfiguration.cpp b/src/playback/internal/playbackconfiguration.cpp index 24402b968f798..217772dbbd27d 100644 --- a/src/playback/internal/playbackconfiguration.cpp +++ b/src/playback/internal/playbackconfiguration.cpp @@ -92,8 +92,17 @@ static Settings::Key auxChannelVisibleKey(aux_channel_idx_t index) void PlaybackConfiguration::init() { settings()->setDefaultValue(PLAY_NOTES_WHEN_EDITING, Val(true)); + settings()->valueChanged(PLAY_NOTES_WHEN_EDITING).onReceive(this, [this](const Val& val) { + m_playNotesWhenEditingChanged.send(val.toBool()); + }); settings()->setDefaultValue(PLAY_CHORD_WHEN_EDITING, Val(true)); + settings()->valueChanged(PLAY_CHORD_WHEN_EDITING).onReceive(this, [this](const Val& val) { + m_playChordWhenEditingChanged.send(val.toBool()); + }); settings()->setDefaultValue(PLAY_HARMONY_WHEN_EDITING, Val(true)); + settings()->valueChanged(PLAY_HARMONY_WHEN_EDITING).onReceive(this, [this](const Val& val) { + m_playHarmonyWhenEditingChanged.send(val.toBool()); + }); settings()->setDefaultValue(PLAYBACK_CURSOR_TYPE_KEY, Val(PlaybackCursorType::STEPPED)); settings()->setDefaultValue(SOUND_PRESETS_MULTI_SELECTION_KEY, Val(false)); settings()->setDefaultValue(MIXER_RESET_SOUND_FLAGS_WHEN_CHANGE_SOUND_WARNING, Val(true)); @@ -141,6 +150,11 @@ void PlaybackConfiguration::setPlayNotesWhenEditing(bool value) settings()->setSharedValue(PLAY_NOTES_WHEN_EDITING, Val(value)); } +async::Channel PlaybackConfiguration::playNotesWhenEditingChanged() const +{ + return m_playNotesWhenEditingChanged; +} + bool PlaybackConfiguration::playChordWhenEditing() const { return settings()->value(PLAY_CHORD_WHEN_EDITING).toBool(); @@ -151,6 +165,11 @@ void PlaybackConfiguration::setPlayChordWhenEditing(bool value) settings()->setSharedValue(PLAY_CHORD_WHEN_EDITING, Val(value)); } +async::Channel PlaybackConfiguration::playChordWhenEditingChanged() const +{ + return m_playChordWhenEditingChanged; +} + bool PlaybackConfiguration::playHarmonyWhenEditing() const { return settings()->value(PLAY_HARMONY_WHEN_EDITING).toBool(); @@ -161,6 +180,11 @@ void PlaybackConfiguration::setPlayHarmonyWhenEditing(bool value) settings()->setSharedValue(PLAY_HARMONY_WHEN_EDITING, Val(value)); } +async::Channel PlaybackConfiguration::playHarmonyWhenEditingChanged() const +{ + return m_playHarmonyWhenEditingChanged; +} + PlaybackCursorType PlaybackConfiguration::cursorType() const { return settings()->value(PLAYBACK_CURSOR_TYPE_KEY).toEnum(); diff --git a/src/playback/internal/playbackconfiguration.h b/src/playback/internal/playbackconfiguration.h index 8cd8f1670856c..829479f3e17c8 100644 --- a/src/playback/internal/playbackconfiguration.h +++ b/src/playback/internal/playbackconfiguration.h @@ -40,12 +40,15 @@ class PlaybackConfiguration : public IPlaybackConfiguration, public muse::async: bool playNotesWhenEditing() const override; void setPlayNotesWhenEditing(bool value) override; + muse::async::Channel playNotesWhenEditingChanged() const override; bool playChordWhenEditing() const override; void setPlayChordWhenEditing(bool value) override; + muse::async::Channel playChordWhenEditingChanged() const override; bool playHarmonyWhenEditing() const override; void setPlayHarmonyWhenEditing(bool value) override; + muse::async::Channel playHarmonyWhenEditingChanged() const override; PlaybackCursorType cursorType() const override; @@ -87,6 +90,9 @@ class PlaybackConfiguration : public IPlaybackConfiguration, public muse::async: private: const SoundProfileName& fallbackSoundProfileStr() const; + muse::async::Channel m_playNotesWhenEditingChanged; + muse::async::Channel m_playChordWhenEditingChanged; + muse::async::Channel m_playHarmonyWhenEditingChanged; muse::async::Channel m_isAuxSendVisibleChanged; muse::async::Channel m_isAuxChannelVisibleChanged; muse::async::Channel m_isMixerSectionVisibleChanged; diff --git a/src/playback/iplaybackconfiguration.h b/src/playback/iplaybackconfiguration.h index 562a830e03e95..d173fa6dda54c 100644 --- a/src/playback/iplaybackconfiguration.h +++ b/src/playback/iplaybackconfiguration.h @@ -36,12 +36,15 @@ class IPlaybackConfiguration : MODULE_EXPORT_INTERFACE virtual bool playNotesWhenEditing() const = 0; virtual void setPlayNotesWhenEditing(bool value) = 0; + virtual muse::async::Channel playNotesWhenEditingChanged() const = 0; virtual bool playChordWhenEditing() const = 0; virtual void setPlayChordWhenEditing(bool value) = 0; + virtual muse::async::Channel playChordWhenEditingChanged() const = 0; virtual bool playHarmonyWhenEditing() const = 0; virtual void setPlayHarmonyWhenEditing(bool value) = 0; + virtual muse::async::Channel playHarmonyWhenEditingChanged() const = 0; virtual PlaybackCursorType cursorType() const = 0; diff --git a/src/project/internal/projectconfiguration.cpp b/src/project/internal/projectconfiguration.cpp index 58b182f94da0a..f70dd8d8710cc 100644 --- a/src/project/internal/projectconfiguration.cpp +++ b/src/project/internal/projectconfiguration.cpp @@ -114,7 +114,13 @@ void ProjectConfiguration::init() settings()->setDefaultValue(OPEN_DETAILED_PROJECT_UPLOADED_DIALOG, Val(true)); settings()->setDefaultValue(HAS_ASKED_AUDIO_GENERATION_SETTINGS, Val(false)); settings()->setDefaultValue(GENERATE_AUDIO_TIME_PERIOD_TYPE_KEY, Val(static_cast(GenerateAudioTimePeriodType::Never))); + settings()->valueChanged(GENERATE_AUDIO_TIME_PERIOD_TYPE_KEY).onReceive(nullptr, [this](const Val& val) { + m_generateAudioTimePeriodTypeChanged.send(val.toInt()); + }); settings()->setDefaultValue(NUMBER_OF_SAVES_TO_GENERATE_AUDIO_KEY, Val(10)); + settings()->valueChanged(NUMBER_OF_SAVES_TO_GENERATE_AUDIO_KEY).onReceive(nullptr, [this](const Val& val) { + m_numberOfSavesToGenerateAudioChanged.send(val.toInt()); + }); settings()->setDefaultValue(SHOW_CLOUD_IS_NOT_AVAILABLE_WARNING, Val(true)); settings()->setDefaultValue(DISABLE_VERSION_CHECKING, Val(false)); @@ -645,6 +651,11 @@ void ProjectConfiguration::setGenerateAudioTimePeriodType(GenerateAudioTimePerio settings()->setSharedValue(GENERATE_AUDIO_TIME_PERIOD_TYPE_KEY, Val(static_cast(type))); } +muse::async::Channel ProjectConfiguration::generateAudioTimePeriodTypeChanged() const +{ + return m_generateAudioTimePeriodTypeChanged; +} + int ProjectConfiguration::numberOfSavesToGenerateAudio() const { return settings()->value(NUMBER_OF_SAVES_TO_GENERATE_AUDIO_KEY).toInt(); @@ -655,6 +666,11 @@ void ProjectConfiguration::setNumberOfSavesToGenerateAudio(int number) settings()->setSharedValue(NUMBER_OF_SAVES_TO_GENERATE_AUDIO_KEY, Val(number)); } +muse::async::Channel ProjectConfiguration::numberOfSavesToGenerateAudioChanged() const +{ + return m_numberOfSavesToGenerateAudioChanged; +} + muse::io::path_t ProjectConfiguration::temporaryMp3FilePathTemplate() const { return globalConfiguration()->userAppDataPath() + "/audioFile_XXXXXX.mp3"; diff --git a/src/project/internal/projectconfiguration.h b/src/project/internal/projectconfiguration.h index d82694f56da65..b2a28564c4158 100644 --- a/src/project/internal/projectconfiguration.h +++ b/src/project/internal/projectconfiguration.h @@ -142,8 +142,11 @@ class ProjectConfiguration : public IProjectConfiguration GenerateAudioTimePeriodType generateAudioTimePeriodType() const override; void setGenerateAudioTimePeriodType(GenerateAudioTimePeriodType type) override; + muse::async::Channel generateAudioTimePeriodTypeChanged() const override; + int numberOfSavesToGenerateAudio() const override; void setNumberOfSavesToGenerateAudio(int number) override; + muse::async::Channel numberOfSavesToGenerateAudioChanged() const override; muse::io::path_t temporaryMp3FilePathTemplate() const override; @@ -172,6 +175,9 @@ class ProjectConfiguration : public IProjectConfiguration muse::async::Channel m_autoSaveEnabledChanged; muse::async::Channel m_autoSaveIntervalChanged; + muse::async::Channel m_generateAudioTimePeriodTypeChanged; + muse::async::Channel m_numberOfSavesToGenerateAudioChanged; + muse::async::Channel m_alsoShareAudioComChanged; mutable std::map m_migrationOptions; diff --git a/src/project/iprojectconfiguration.h b/src/project/iprojectconfiguration.h index e7447745ff2a4..1e7115c4069df 100644 --- a/src/project/iprojectconfiguration.h +++ b/src/project/iprojectconfiguration.h @@ -147,9 +147,11 @@ class IProjectConfiguration : MODULE_EXPORT_INTERFACE virtual GenerateAudioTimePeriodType generateAudioTimePeriodType() const = 0; virtual void setGenerateAudioTimePeriodType(GenerateAudioTimePeriodType type) = 0; + virtual muse::async::Channel generateAudioTimePeriodTypeChanged() const = 0; virtual int numberOfSavesToGenerateAudio() const = 0; virtual void setNumberOfSavesToGenerateAudio(int number) = 0; + virtual muse::async::Channel numberOfSavesToGenerateAudioChanged() const = 0; virtual muse::io::path_t temporaryMp3FilePathTemplate() const = 0; diff --git a/src/project/qml/MuseScore/Project/AudioGenerationSettings.qml b/src/project/qml/MuseScore/Project/AudioGenerationSettings.qml index 483cb4dbcd1f2..edcf349c67f34 100644 --- a/src/project/qml/MuseScore/Project/AudioGenerationSettings.qml +++ b/src/project/qml/MuseScore/Project/AudioGenerationSettings.qml @@ -55,6 +55,10 @@ RadioButtonGroup { id: settingsModel } + Component.onCompleted: { + settingsModel.load() + } + model: [ { text: qsTrc("project/save", "Never"), type: GenerateAudioTimePeriodType.Never }, { text: qsTrc("project/save", "Always"), type: GenerateAudioTimePeriodType.Always }, diff --git a/src/project/tests/mocks/projectconfigurationmock.h b/src/project/tests/mocks/projectconfigurationmock.h index c55aee2c80430..b6096bd05c6e4 100644 --- a/src/project/tests/mocks/projectconfigurationmock.h +++ b/src/project/tests/mocks/projectconfigurationmock.h @@ -124,9 +124,11 @@ class ProjectConfigurationMock : public project::IProjectConfiguration MOCK_METHOD(GenerateAudioTimePeriodType, generateAudioTimePeriodType, (), (const, override)); MOCK_METHOD(void, setGenerateAudioTimePeriodType, (GenerateAudioTimePeriodType), (override)); + MOCK_METHOD(muse::async::Channel, generateAudioTimePeriodTypeChanged, (), (const, override)); MOCK_METHOD(int, numberOfSavesToGenerateAudio, (), (const, override)); MOCK_METHOD(void, setNumberOfSavesToGenerateAudio, (int), (override)); + MOCK_METHOD(muse::async::Channel, numberOfSavesToGenerateAudioChanged, (), (const, override)); MOCK_METHOD(muse::io::path_t, temporaryMp3FilePathTemplate, (), (const, override)); diff --git a/src/project/view/audiogenerationsettingsmodel.cpp b/src/project/view/audiogenerationsettingsmodel.cpp index d12b628ab41b6..02d8833a38bd7 100644 --- a/src/project/view/audiogenerationsettingsmodel.cpp +++ b/src/project/view/audiogenerationsettingsmodel.cpp @@ -29,6 +29,17 @@ AudioGenerationSettingsModel::AudioGenerationSettingsModel(QObject* parent) { } +void AudioGenerationSettingsModel::load() +{ + configuration()->generateAudioTimePeriodTypeChanged().onReceive(this, [this](int) { + emit timePeriodTypeChanged(); + }); + + configuration()->numberOfSavesToGenerateAudioChanged().onReceive(this, [this](int) { + emit numberOfSavesChanged(); + }); +} + int AudioGenerationSettingsModel::timePeriodType() const { return static_cast(configuration()->generateAudioTimePeriodType()); diff --git a/src/project/view/audiogenerationsettingsmodel.h b/src/project/view/audiogenerationsettingsmodel.h index 34a4e08ab6eaa..0ba5abe3e88de 100644 --- a/src/project/view/audiogenerationsettingsmodel.h +++ b/src/project/view/audiogenerationsettingsmodel.h @@ -28,7 +28,7 @@ #include "iprojectconfiguration.h" namespace mu::project { -class AudioGenerationSettingsModel : public QObject +class AudioGenerationSettingsModel : public QObject, public muse::async::Asyncable { Q_OBJECT @@ -40,6 +40,8 @@ class AudioGenerationSettingsModel : public QObject public: explicit AudioGenerationSettingsModel(QObject* parent = nullptr); + Q_INVOKABLE void load(); + int timePeriodType() const; int numberOfSaves() const; diff --git a/src/stubs/notation/notationconfigurationstub.cpp b/src/stubs/notation/notationconfigurationstub.cpp index e4a4c28b8319b..ab99f06dd00ed 100644 --- a/src/stubs/notation/notationconfigurationstub.cpp +++ b/src/stubs/notation/notationconfigurationstub.cpp @@ -164,6 +164,12 @@ void NotationConfigurationStub::setSelectionProximity(int) { } +muse::async::Channel NotationConfigurationStub::selectionProximityChanged() const +{ + static muse::async::Channel ch; + return ch; +} + ZoomType NotationConfigurationStub::defaultZoomType() const { return ZoomType::PageWidth; @@ -182,6 +188,12 @@ void NotationConfigurationStub::setDefaultZoom(int) { } +muse::async::Notification NotationConfigurationStub::defaultZoomChanged() const +{ + static muse::async::Notification n; + return n; +} + QList NotationConfigurationStub::possibleZoomPercentageList() const { return QList(); @@ -206,6 +218,12 @@ void NotationConfigurationStub::setMouseZoomPrecision(int) { } +muse::async::Notification NotationConfigurationStub::mouseZoomPrecisionChanged() const +{ + static muse::async::Notification n; + return n; +} + std::string NotationConfigurationStub::fontFamily() const { return std::string(); @@ -240,6 +258,12 @@ void NotationConfigurationStub::setDefaultStyleFilePath(const muse::io::path_t&) { } +muse::async::Channel NotationConfigurationStub::defaultStyleFilePathChanged() const +{ + static muse::async::Channel ch; + return ch; +} + muse::io::path_t NotationConfigurationStub::partStyleFilePath() const { return muse::io::path_t(); @@ -249,6 +273,12 @@ void NotationConfigurationStub::setPartStyleFilePath(const muse::io::path_t&) { } +muse::async::Channel NotationConfigurationStub::partStyleFilePathChanged() const +{ + static muse::async::Channel ch; + return ch; +} + bool NotationConfigurationStub::isMidiInputEnabled() const { return false; @@ -359,6 +389,12 @@ void NotationConfigurationStub::setColorNotesOutsideOfUsablePitchRange(bool) { } +muse::async::Channel NotationConfigurationStub::colorNotesOutsideOfUsablePitchRangeChanged() const +{ + static muse::async::Channel ch; + return ch; +} + int NotationConfigurationStub::delayBetweenNotesInRealTimeModeMilliseconds() const { return 100; @@ -368,6 +404,12 @@ void NotationConfigurationStub::setDelayBetweenNotesInRealTimeModeMilliseconds(i { } +muse::async::Channel NotationConfigurationStub::delayBetweenNotesInRealTimeModeMillisecondsChanged() const +{ + static muse::async::Channel ch; + return ch; +} + int NotationConfigurationStub::notePlayDurationMilliseconds() const { return 100; @@ -377,6 +419,12 @@ void NotationConfigurationStub::setNotePlayDurationMilliseconds(int) { } +muse::async::Channel NotationConfigurationStub::notePlayDurationMillisecondsChanged() const +{ + static muse::async::Channel ch; + return ch; +} + void NotationConfigurationStub::setTemplateModeEnabled(std::optional) { } @@ -501,3 +549,9 @@ muse::io::path_t NotationConfigurationStub::styleFileImportPath() const void NotationConfigurationStub::setStyleFileImportPath(const muse::io::path_t&) { } + +muse::async::Channel NotationConfigurationStub::styleFileImportPathChanged() const +{ + static muse::async::Channel ch; + return ch; +} diff --git a/src/stubs/notation/notationconfigurationstub.h b/src/stubs/notation/notationconfigurationstub.h index 0ebedae9e6572..fbf69aac72e64 100644 --- a/src/stubs/notation/notationconfigurationstub.h +++ b/src/stubs/notation/notationconfigurationstub.h @@ -75,6 +75,7 @@ class NotationConfigurationStub : public INotationConfiguration int selectionProximity() const override; void setSelectionProximity(int proximity) override; + muse::async::Channel selectionProximityChanged() const override; ZoomType defaultZoomType() const override; void setDefaultZoomType(ZoomType zoomType) override; @@ -82,6 +83,8 @@ class NotationConfigurationStub : public INotationConfiguration int defaultZoom() const override; void setDefaultZoom(int zoomPercentage) override; + muse::async::Notification defaultZoomChanged() const override; + QList possibleZoomPercentageList() const override; qreal scalingFromZoomPercentage(int zoomPercentage) const override; @@ -89,6 +92,7 @@ class NotationConfigurationStub : public INotationConfiguration int mouseZoomPrecision() const override; void setMouseZoomPrecision(int precision) override; + muse::async::Notification mouseZoomPrecisionChanged() const override; std::string fontFamily() const override; int fontSize() const override; @@ -99,9 +103,11 @@ class NotationConfigurationStub : public INotationConfiguration muse::io::path_t defaultStyleFilePath() const override; void setDefaultStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel defaultStyleFilePathChanged() const override; muse::io::path_t partStyleFilePath() const override; void setPartStyleFilePath(const muse::io::path_t& path) override; + muse::async::Channel partStyleFilePathChanged() const override; bool isMidiInputEnabled() const override; void setIsMidiInputEnabled(bool enabled) override; @@ -135,12 +141,15 @@ class NotationConfigurationStub : public INotationConfiguration bool colorNotesOutsideOfUsablePitchRange() const override; void setColorNotesOutsideOfUsablePitchRange(bool value) override; + muse::async::Channel colorNotesOutsideOfUsablePitchRangeChanged() const override; int delayBetweenNotesInRealTimeModeMilliseconds() const override; void setDelayBetweenNotesInRealTimeModeMilliseconds(int delayMs) override; + muse::async::Channel delayBetweenNotesInRealTimeModeMillisecondsChanged() const override; int notePlayDurationMilliseconds() const override; void setNotePlayDurationMilliseconds(int durationMs) override; + muse::async::Channel notePlayDurationMillisecondsChanged() const override; void setTemplateModeEnabled(std::optional enabled) override; void setTestModeEnabled(std::optional enabled) override; @@ -182,6 +191,7 @@ class NotationConfigurationStub : public INotationConfiguration muse::io::path_t styleFileImportPath() const override; void setStyleFileImportPath(const muse::io::path_t& path) override; + muse::async::Channel styleFileImportPathChanged() const override; }; } diff --git a/src/stubs/playback/playbackconfigurationstub.cpp b/src/stubs/playback/playbackconfigurationstub.cpp index d33e287508a23..45dafb1cd6027 100644 --- a/src/stubs/playback/playbackconfigurationstub.cpp +++ b/src/stubs/playback/playbackconfigurationstub.cpp @@ -33,6 +33,12 @@ void PlaybackConfigurationStub::setPlayNotesWhenEditing(bool) { } +muse::async::Channel PlaybackConfigurationStub::playNotesWhenEditingChanged() const +{ + static muse::async::Channel ch; + return ch; +} + bool PlaybackConfigurationStub::playChordWhenEditing() const { return false; @@ -42,6 +48,12 @@ void PlaybackConfigurationStub::setPlayChordWhenEditing(bool) { } +muse::async::Channel PlaybackConfigurationStub::playChordWhenEditingChanged() const +{ + static muse::async::Channel ch; + return ch; +} + bool PlaybackConfigurationStub::playHarmonyWhenEditing() const { return false; @@ -51,6 +63,12 @@ void PlaybackConfigurationStub::setPlayHarmonyWhenEditing(bool) { } +muse::async::Channel PlaybackConfigurationStub::playHarmonyWhenEditingChanged() const +{ + static muse::async::Channel ch; + return ch; +} + PlaybackCursorType PlaybackConfigurationStub::cursorType() const { return PlaybackCursorType::SMOOTH; diff --git a/src/stubs/playback/playbackconfigurationstub.h b/src/stubs/playback/playbackconfigurationstub.h index 9e5965eb5006e..df8fb0ca9a1a2 100644 --- a/src/stubs/playback/playbackconfigurationstub.h +++ b/src/stubs/playback/playbackconfigurationstub.h @@ -30,12 +30,15 @@ class PlaybackConfigurationStub : public IPlaybackConfiguration public: bool playNotesWhenEditing() const override; void setPlayNotesWhenEditing(bool value) override; + muse::async::Channel playNotesWhenEditingChanged() const override; bool playChordWhenEditing() const override; void setPlayChordWhenEditing(bool value) override; + muse::async::Channel playChordWhenEditingChanged() const override; bool playHarmonyWhenEditing() const override; void setPlayHarmonyWhenEditing(bool value) override; + muse::async::Channel playHarmonyWhenEditingChanged() const override; PlaybackCursorType cursorType() const override; diff --git a/src/stubs/project/projectconfigurationstub.cpp b/src/stubs/project/projectconfigurationstub.cpp index 2071f125899c8..191e04a3746cc 100644 --- a/src/stubs/project/projectconfigurationstub.cpp +++ b/src/stubs/project/projectconfigurationstub.cpp @@ -296,6 +296,12 @@ void ProjectConfigurationStub::setGenerateAudioTimePeriodType(GenerateAudioTimeP { } +muse::async::Channel ProjectConfigurationStub::generateAudioTimePeriodTypeChanged() const +{ + static muse::async::Channel ch; + return ch; +} + int ProjectConfigurationStub::numberOfSavesToGenerateAudio() const { return 1; @@ -305,6 +311,12 @@ void ProjectConfigurationStub::setNumberOfSavesToGenerateAudio(int) { } +muse::async::Channel ProjectConfigurationStub::numberOfSavesToGenerateAudioChanged() const +{ + static muse::async::Channel ch; + return ch; +} + muse::io::path_t ProjectConfigurationStub::temporaryMp3FilePathTemplate() const { return muse::io::path_t(); diff --git a/src/stubs/project/projectconfigurationstub.h b/src/stubs/project/projectconfigurationstub.h index 86b1f2bf21ea8..10b3d93c8b0cc 100644 --- a/src/stubs/project/projectconfigurationstub.h +++ b/src/stubs/project/projectconfigurationstub.h @@ -115,9 +115,11 @@ class ProjectConfigurationStub : public IProjectConfiguration GenerateAudioTimePeriodType generateAudioTimePeriodType() const override; void setGenerateAudioTimePeriodType(GenerateAudioTimePeriodType type) override; + muse::async::Channel generateAudioTimePeriodTypeChanged() const override; int numberOfSavesToGenerateAudio() const override; void setNumberOfSavesToGenerateAudio(int number) override; + muse::async::Channel numberOfSavesToGenerateAudioChanged() const override; muse::io::path_t temporaryMp3FilePathTemplate() const override;