diff --git a/share/styles/CMakeLists.txt b/share/styles/CMakeLists.txt index a5613cd4a252b..4710cb62ef07b 100644 --- a/share/styles/CMakeLists.txt +++ b/share/styles/CMakeLists.txt @@ -31,4 +31,4 @@ install(FILES cchords_sym.xml DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}styles ) - +add_subdirectory(MSN) diff --git a/share/styles/MSN/CMakeLists.txt b/share/styles/MSN/CMakeLists.txt new file mode 100644 index 0000000000000..04250f2dbc904 --- /dev/null +++ b/share/styles/MSN/CMakeLists.txt @@ -0,0 +1,8 @@ +install(FILES + 16mm_MSN.mss + 18mm_MSN.mss + 20mm_MSN.mss + 22mm_MSN.mss + 25mm_MSN.mss + DESTINATION ${Mscore_SHARE_NAME}${Mscore_INSTALL_NAME}styles/MSN + ) diff --git a/src/engraving/style/style.cpp b/src/engraving/style/style.cpp index b8b47e34bf0e2..f1fab1c19b1ee 100644 --- a/src/engraving/style/style.cpp +++ b/src/engraving/style/style.cpp @@ -293,6 +293,8 @@ bool MStyle::read(IODevice* device, bool ign) readVersion(e.attribute("version")); while (e.readNextStartElement()) { if (e.name() == "Style") { + m_preset = TConv::fromXml(e.asciiAttribute("preset", "Default"), ScoreStylePreset::DEFAULT); + m_presetedited = e.attribute("edited", String(u"false")) == "true"; read(e, nullptr); } else { e.unknown(); @@ -542,7 +544,17 @@ bool MStyle::write(IODevice* device) void MStyle::save(XmlWriter& xml, bool optimize) { - xml.startElement("Style"); + muse::XmlStreamWriter::Attributes attributes; + + if (preset() != ScoreStylePreset::DEFAULT) { + attributes.push_back({ "preset", TConv::toXml(preset()) }); + } + + if (presetEdited()) { + attributes.push_back({ "edited", String(u"true") }); + } + + xml.startElement("Style", attributes); for (const StyleDef::StyleValue& st : StyleDef::styleValues) { Sid idx = st.styleIdx(); diff --git a/src/engraving/style/style.h b/src/engraving/style/style.h index 4012655e45d3f..d335d735156be 100644 --- a/src/engraving/style/style.h +++ b/src/engraving/style/style.h @@ -74,6 +74,11 @@ class MStyle void setDefaultStyleVersion(const int defaultsVersion); int defaultStyleVersion() const; + ScoreStylePreset preset() const { return m_preset; } + void setPreset(ScoreStylePreset preset) { m_preset = preset; } + bool presetEdited() const { return m_presetedited; } + void setPresetEdited(bool isEdited) { m_presetedited = isEdited; } + bool read(muse::io::IODevice* device, bool ign = false); bool write(muse::io::IODevice* device); void save(XmlWriter& xml, bool optimize); @@ -100,6 +105,8 @@ class MStyle void readVersion(String versionTag); int m_version = 0; + ScoreStylePreset m_preset = ScoreStylePreset::DEFAULT; + bool m_presetedited = false; }; } // namespace mu::engraving diff --git a/src/engraving/types/types.h b/src/engraving/types/types.h index 55695d42f7ab5..2837d55a471e5 100644 --- a/src/engraving/types/types.h +++ b/src/engraving/types/types.h @@ -1161,6 +1161,16 @@ struct std::hash } }; +enum class ScoreStylePreset { + DEFAULT = 0, + MSN_16MM, + MSN_18MM, + MSN_20MM, + MSN_22MM, + MSN_25MM, + MAX_PRESET +}; + #ifndef NO_QT_SUPPORT Q_DECLARE_METATYPE(mu::engraving::BeamMode) Q_DECLARE_METATYPE(mu::engraving::JumpType) diff --git a/src/engraving/types/typesconv.cpp b/src/engraving/types/typesconv.cpp index 98e61b5b87c56..476ddcc059cbd 100644 --- a/src/engraving/types/typesconv.cpp +++ b/src/engraving/types/typesconv.cpp @@ -2746,3 +2746,42 @@ String TConv::translatedUserName(Key v, bool isAtonal, bool isCustom) { return userName(v, isAtonal, isCustom).translated(); } + +const std::array, 6> SCORE_STYLE_PRESETS = { { + //: Score notation style: Default + { ScoreStylePreset::DEFAULT, "Default", muse::TranslatableString("engraving/scorestylepreset", "Default") }, + //: Score notation style: Modified Stave Notation (MSN) with 16mm staff size. Intended for visually-impaired musicians. + { ScoreStylePreset::MSN_16MM, "16mm MSN", muse::TranslatableString("engraving/scorestylepreset", "16mm MSN") }, + //: Score notation style: Modified Stave Notation (MSN) with 18mm staff size. Intended for visually-impaired musicians. + { ScoreStylePreset::MSN_18MM, "18mm MSN", muse::TranslatableString("engraving/scorestylepreset", "18mm MSN") }, + //: Score notation style: Modified Stave Notation (MSN) with 20mm staff size. Intended for visually-impaired musicians. + { ScoreStylePreset::MSN_20MM, "20mm MSN", muse::TranslatableString("engraving/scorestylepreset", "20mm MSN") }, + //: Score notation style: Modified Stave Notation (MSN) with 22mm staff size. Intended for visually-impaired musicians. + { ScoreStylePreset::MSN_22MM, "22mm MSN", muse::TranslatableString("engraving/scorestylepreset", "22mm MSN") }, + //: Score notation style: Modified Stave Notation (MSN) with 25mm staff size. Intended for visually-impaired musicians. + { ScoreStylePreset::MSN_25MM, "25mm MSN", muse::TranslatableString("engraving/scorestylepreset", "25mm MSN") } +} }; + +AsciiStringView TConv::toXml(ScoreStylePreset preset) +{ + return findXmlTagByType(SCORE_STYLE_PRESETS, preset); +} + +ScoreStylePreset TConv::fromXml(const AsciiStringView& tag, ScoreStylePreset def) +{ + if (tag == "Default") { + return def; + } + + return findTypeByXmlTag(SCORE_STYLE_PRESETS, tag, def); +} + +const muse::TranslatableString& TConv::userName(ScoreStylePreset v) +{ + return findUserNameByType(SCORE_STYLE_PRESETS, v); +} + +String TConv::translatedUserName(ScoreStylePreset v) +{ + return findUserNameByType(SCORE_STYLE_PRESETS, v).translated(); +} diff --git a/src/engraving/types/typesconv.h b/src/engraving/types/typesconv.h index 43fb77b441a20..32547eaeaf187 100644 --- a/src/engraving/types/typesconv.h +++ b/src/engraving/types/typesconv.h @@ -245,6 +245,12 @@ class TConv static AsciiStringView toXml(AutoOnOff autoOnOff); static AutoOnOff fromXml(const AsciiStringView& str, AutoOnOff def); + + static AsciiStringView toXml(ScoreStylePreset preset); + static ScoreStylePreset fromXml(const AsciiStringView& tag, ScoreStylePreset def); + + static const TranslatableString& userName(ScoreStylePreset v); + static String translatedUserName(ScoreStylePreset v); }; } diff --git a/src/inspector/CMakeLists.txt b/src/inspector/CMakeLists.txt index 9806b49e81d72..2e1eb52636362 100644 --- a/src/inspector/CMakeLists.txt +++ b/src/inspector/CMakeLists.txt @@ -86,6 +86,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/models/measures/measuressettingsmodel.h ${CMAKE_CURRENT_LIST_DIR}/models/score/scoreappearancesettingsmodel.cpp ${CMAKE_CURRENT_LIST_DIR}/models/score/scoreappearancesettingsmodel.h + ${CMAKE_CURRENT_LIST_DIR}/models/score/scoreaccessibilitysettingsmodel.cpp + ${CMAKE_CURRENT_LIST_DIR}/models/score/scoreaccessibilitysettingsmodel.h ${CMAKE_CURRENT_LIST_DIR}/models/score/scoredisplaysettingsmodel.cpp ${CMAKE_CURRENT_LIST_DIR}/models/score/scoredisplaysettingsmodel.h ${CMAKE_CURRENT_LIST_DIR}/models/score/internal/pagetypelistmodel.cpp diff --git a/src/inspector/models/abstractinspectormodel.h b/src/inspector/models/abstractinspectormodel.h index dcb3b3eda10ba..034e4e42af8df 100644 --- a/src/inspector/models/abstractinspectormodel.h +++ b/src/inspector/models/abstractinspectormodel.h @@ -65,6 +65,7 @@ class AbstractInspectorModel : public QObject, public muse::async::Asyncable SECTION_TEXT, SECTION_SCORE_DISPLAY, SECTION_SCORE_APPEARANCE, + SECTION_SCORE_ACCESSIBILITY, SECTION_PARTS, }; Q_ENUM(InspectorSectionType) diff --git a/src/inspector/models/inspectorlistmodel.cpp b/src/inspector/models/inspectorlistmodel.cpp index 212951ddb1f05..bae2afc954328 100644 --- a/src/inspector/models/inspectorlistmodel.cpp +++ b/src/inspector/models/inspectorlistmodel.cpp @@ -28,6 +28,7 @@ #include "text/textsettingsmodel.h" #include "score/scoredisplaysettingsmodel.h" #include "score/scoreappearancesettingsmodel.h" +#include "score/scoreaccessibilitysettingsmodel.h" #include "notation/inotationinteraction.h" #include "internal/services/elementrepositoryservice.h" @@ -73,7 +74,8 @@ void InspectorListModel::buildModelsForEmptySelection() static const InspectorSectionTypeSet persistentSections { InspectorSectionType::SECTION_SCORE_DISPLAY, - InspectorSectionType::SECTION_SCORE_APPEARANCE + InspectorSectionType::SECTION_SCORE_APPEARANCE, + InspectorSectionType::SECTION_SCORE_ACCESSIBILITY }; removeUnusedModels({}, false /*isRangeSelection*/, {}, persistentSections); @@ -195,6 +197,9 @@ void InspectorListModel::createModelsBySectionType(const InspectorSectionTypeSet case InspectorSectionType::SECTION_SCORE_APPEARANCE: newModel = new ScoreAppearanceSettingsModel(this, m_repository); break; + case InspectorSectionType::SECTION_SCORE_ACCESSIBILITY: + newModel = new ScoreAccessibilitySettingsModel(this, m_repository); + break; case InspectorSectionType::SECTION_PARTS: newModel = new PartsSettingsModel(this, m_repository); break; diff --git a/src/inspector/models/score/scoreaccessibilitysettingsmodel.cpp b/src/inspector/models/score/scoreaccessibilitysettingsmodel.cpp new file mode 100644 index 0000000000000..2931b59b273df --- /dev/null +++ b/src/inspector/models/score/scoreaccessibilitysettingsmodel.cpp @@ -0,0 +1,215 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "scoreaccessibilitysettingsmodel.h" + +#include "translation.h" +#include "log.h" +#include "engraving/types/typesconv.h" +#include "framework/global/defer.h" + +using namespace mu::inspector; +using namespace mu::engraving; + +ScoreAccessibilitySettingsModel::ScoreAccessibilitySettingsModel(QObject* parent, IElementRepositoryService* repository) + : AbstractInspectorModel(parent, repository) +{ + setSectionType(InspectorSectionType::SECTION_SCORE_ACCESSIBILITY); + setTitle(muse::qtrc("inspector", "Accessibility")); + + globalContext()->currentNotation()->style()->styleChanged().onNotify(this, [this]() { + if (!m_ignoreStyleChange && !m_scoreStylePresetEdited) { + m_scoreStylePresetEdited = true; + globalContext()->currentNotation()->elements()->msScore()->score()->style().setPresetEdited(true); + emit possibleScoreStylePresetsChanged(); + emit scoreStylePresetIndexChanged(); + } + }); +} + +void ScoreAccessibilitySettingsModel::createProperties() +{ + // Placeholder +} + +void ScoreAccessibilitySettingsModel::requestElements() +{ + // Placeholder +} + +void ScoreAccessibilitySettingsModel::loadProperties() +{ + // Placeholder +} + +void ScoreAccessibilitySettingsModel::resetProperties() +{ + // Placeholder +} + +muse::io::path_t ScoreAccessibilitySettingsModel::getStyleFilePath(ScoreStylePreset preset) const +{ + muse::io::path_t basePath = globalConfiguration()->appDataPath() + "styles/MSN/"; + switch (preset) { + case ScoreStylePreset::DEFAULT: + return engravingConfiguration()->defaultStyleFilePath(); + case ScoreStylePreset::MSN_16MM: + return basePath + "16mm_MSN.mss"; + case ScoreStylePreset::MSN_18MM: + return basePath + "18mm_MSN.mss"; + case ScoreStylePreset::MSN_20MM: + return basePath + "20mm_MSN.mss"; + case ScoreStylePreset::MSN_22MM: + return basePath + "22mm_MSN.mss"; + case ScoreStylePreset::MSN_25MM: + return basePath + "25mm_MSN.mss"; + default: + return muse::io::path_t(); + } +} + +QVariantList ScoreAccessibilitySettingsModel::possibleScoreStylePresets() const +{ + QVariantList presets; + + QString text = "text"; + QString value = "value"; + QString preset = "preset"; + QString edited = "edited"; + + for (int i = 0; i < static_cast(ScoreStylePreset::MAX_PRESET); ++i) { + ScoreStylePreset presetEnum = static_cast(i); + QString presetName = TConv::translatedUserName(presetEnum); + + presets.append(QVariantMap { + { text, presetName }, + { + value, + QVariantMap { + { preset, i }, + { edited, false } + } + } + }); + + if (i == static_cast(m_scoreStylePreset) && m_scoreStylePresetEdited) { + QString editedPresetName = muse::qtrc("inspector", "%1 (edited)").arg(presetName); + presets.append(QVariantMap { + { text, editedPresetName }, + { + value, + QVariantMap { + { preset, i }, + { edited, true } + } + } + }); + } + } + + return presets; +} + +void ScoreAccessibilitySettingsModel::setScoreStylePresetIndex(int index) +{ + int oldIndex = scoreStylePresetIndex(); + + if (index == oldIndex) { + return; + } + + if (m_scoreStylePresetEdited && index > oldIndex) { + --index; + } + + auto selectedPreset = static_cast(index); + + bool presetChanged = (selectedPreset != m_scoreStylePreset); + bool editedChanged = (m_scoreStylePresetEdited != false); + + MStyle& style = globalContext()->currentNotation()->elements()->msScore()->score()->style(); + + if (presetChanged) { + loadStyle(selectedPreset); + m_scoreStylePreset = selectedPreset; + style.setPreset(selectedPreset); + + emit scoreStylePresetIndexChanged(); + } + + if (editedChanged) { + m_scoreStylePresetEdited = false; + style.setPresetEdited(false); + + emit possibleScoreStylePresetsChanged(); + emit scoreStylePresetIndexChanged(); + } +} + +void ScoreAccessibilitySettingsModel::loadStyle(ScoreStylePreset preset) +{ + muse::io::path_t filePath = getStyleFilePath(preset); + m_ignoreStyleChange = true; + DEFER { + m_ignoreStyleChange = false; + }; + + if (preset == ScoreStylePreset::DEFAULT && filePath.empty()) { + StyleIdSet emptySet; + globalContext()->currentNotation()->style()->resetAllStyleValues(emptySet); + return; + } + + IF_ASSERT_FAILED(!filePath.empty()) { + return; + } + + LOGI() << "Loading style from filePath: " << filePath; + globalContext()->currentNotation()->style()->loadStyle(filePath, true); +} + +int ScoreAccessibilitySettingsModel::scoreStylePresetIndex() const +{ + return static_cast(m_scoreStylePreset) + (m_scoreStylePresetEdited ? 1 : 0); +} + +void ScoreAccessibilitySettingsModel::updateScoreStylePreset() +{ + MStyle style = globalContext()->currentNotation()->elements()->msScore()->score()->style(); + ScoreStylePreset stylePreset = style.preset(); + bool stylePresetEdited = style.presetEdited(); + bool indexChanged = false; + + if (m_scoreStylePreset != stylePreset) { + m_scoreStylePreset = stylePreset; + indexChanged = true; + } + + if (m_scoreStylePresetEdited != stylePresetEdited) { + m_scoreStylePresetEdited = stylePresetEdited; + emit possibleScoreStylePresetsChanged(); + indexChanged = true; + } + + if (indexChanged) { + emit scoreStylePresetIndexChanged(); + } +} diff --git a/src/inspector/models/score/scoreaccessibilitysettingsmodel.h b/src/inspector/models/score/scoreaccessibilitysettingsmodel.h new file mode 100644 index 0000000000000..eec8163d7403e --- /dev/null +++ b/src/inspector/models/score/scoreaccessibilitysettingsmodel.h @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#include "models/abstractinspectormodel.h" +#include "context/iglobalcontext.h" +#include "global/iglobalconfiguration.h" +#include "engraving/iengravingconfiguration.h" +#include "engraving/types/types.h" + +namespace mu::inspector { +class ScoreAccessibilitySettingsModel : public AbstractInspectorModel +{ + Q_OBJECT + INJECT(mu::context::IGlobalContext, globalContext) + INJECT(muse::IGlobalConfiguration, globalConfiguration); + INJECT(engraving::IEngravingConfiguration, engravingConfiguration); + + Q_PROPERTY(QVariantList possibleScoreStylePresets READ possibleScoreStylePresets NOTIFY possibleScoreStylePresetsChanged); + Q_PROPERTY(int scoreStylePresetIndex READ scoreStylePresetIndex WRITE setScoreStylePresetIndex NOTIFY scoreStylePresetIndexChanged); +public: + explicit ScoreAccessibilitySettingsModel(QObject* parent, IElementRepositoryService* repository); + + void createProperties() override; + void requestElements() override; + void loadProperties() override; + void resetProperties() override; + + QVariantList possibleScoreStylePresets() const; + int scoreStylePresetIndex() const; + void setScoreStylePresetIndex(int index); + Q_INVOKABLE void updateScoreStylePreset(); + +private: + ScoreStylePreset m_scoreStylePreset = ScoreStylePreset::DEFAULT; + bool m_scoreStylePresetEdited = false; + bool m_ignoreStyleChange = false; + + void loadStyle(ScoreStylePreset preset); + muse::io::path_t getStyleFilePath(ScoreStylePreset preset) const; +signals: + void possibleScoreStylePresetsChanged(); + void scoreStylePresetIndexChanged(); +}; +} diff --git a/src/inspector/view/inspector_resources.qrc b/src/inspector/view/inspector_resources.qrc index 3d99c193f5753..5e0c7f8000b23 100644 --- a/src/inspector/view/inspector_resources.qrc +++ b/src/inspector/view/inspector_resources.qrc @@ -50,6 +50,7 @@ qml/MuseScore/Inspector/notation/fretdiagrams/internal/FretAdvancedSettingsTab.qml qml/MuseScore/Inspector/score/ScoreDisplayInspectorView.qml qml/MuseScore/Inspector/score/ScoreAppearanceInspectorView.qml + qml/MuseScore/Inspector/score/ScoreAccessibilityInspectorView.qml qml/MuseScore/Inspector/score/HideEmptyStavesSettings.qml qml/MuseScore/Inspector/common/InspectorPropertyView.qml qml/MuseScore/Inspector/common/TextSection.qml diff --git a/src/inspector/view/qml/MuseScore/Inspector/InspectorSectionDelegate.qml b/src/inspector/view/qml/MuseScore/Inspector/InspectorSectionDelegate.qml index eaeb93e6db881..e48da2fb2e248 100644 --- a/src/inspector/view/qml/MuseScore/Inspector/InspectorSectionDelegate.qml +++ b/src/inspector/view/qml/MuseScore/Inspector/InspectorSectionDelegate.qml @@ -73,6 +73,7 @@ ExpandableBlank { } case Inspector.SECTION_SCORE_DISPLAY: return scoreSection case Inspector.SECTION_SCORE_APPEARANCE: return scoreAppearanceSection + case Inspector.SECTION_SCORE_ACCESSIBILITY: return scoreAccessibilitySection case Inspector.SECTION_PARTS: return partsSection } @@ -206,6 +207,25 @@ ExpandableBlank { } } + Component { + id: scoreAccessibilitySection + + ScoreAccessibilityInspectorView { + model: root.sectionModel + navigationPanel: root.navigationPanel + navigationRowStart: root.navigation.row + 1 + anchorItem: root.anchorItem + + onEnsureContentVisibleRequested: function(invisibleContentHeight) { + root.ensureContentVisibleRequested(-invisibleContentHeight) + } + + onPopupOpened: { + root.popupOpened(openedPopup, control) + } + } + } + Component { id: partsSection diff --git a/src/inspector/view/qml/MuseScore/Inspector/score/ScoreAccessibilityInspectorView.qml b/src/inspector/view/qml/MuseScore/Inspector/score/ScoreAccessibilityInspectorView.qml new file mode 100644 index 0000000000000..064a04309b957 --- /dev/null +++ b/src/inspector/view/qml/MuseScore/Inspector/score/ScoreAccessibilityInspectorView.qml @@ -0,0 +1,62 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-Studio-CLA-applies + * + * MuseScore Studio + * Music Composition & Notation + * + * Copyright (C) 2021 MuseScore Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import MuseScore.Inspector 1.0 +import Muse.UiComponents 1.0 +import Muse.Ui 1.0 + +import "../common" + +InspectorSectionView { + id: root + + implicitHeight: contentColumn.implicitHeight + + Column { + id: contentColumn + width: parent.width + spacing: 8 + + Text { + text: qsTr("Score style preset") + color: ui.theme.fontPrimaryColor + } + + StyledDropdown { + id: scoreStylePreset + width: parent.width + currentIndex: root.model ? root.model.scoreStylePresetIndex : 0 + model: root.model ? root.model.possibleScoreStylePresets : [] + + Component.onCompleted: { + root.model.updateScoreStylePreset() + } + + onActivated: function(index, value) { + root.model.scoreStylePresetIndex = index + } + } + } +}