Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2024 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "percussionutilities.h"
24 :
25 : #include "engraving/dom/chord.h"
26 : #include "engraving/dom/factory.h"
27 : #include "engraving/dom/masterscore.h"
28 : #include "engraving/dom/note.h"
29 : #include "engraving/dom/stem.h"
30 : #include "engraving/rw/xmlreader.h"
31 :
32 : using namespace mu::notation;
33 : using namespace mu::engraving;
34 :
35 0 : void PercussionUtilities::readDrumset(const muse::ByteArray& drumMapping, Drumset& drumset)
36 : {
37 0 : XmlReader reader(drumMapping);
38 :
39 0 : while (reader.readNextStartElement()) {
40 0 : if (reader.name() == "museScore") {
41 0 : while (reader.readNextStartElement()) {
42 0 : if (reader.name() == "Drum") {
43 0 : drumset.loadDrum(reader);
44 0 : } else if (reader.name() == "percussionPanelColumns") {
45 0 : drumset.setPercussionPanelColumns(reader.readInt());
46 : } else {
47 0 : reader.unknown();
48 : }
49 : }
50 : }
51 : }
52 0 : }
53 :
54 : /// Returns a drum note prepared for preview.
55 0 : std::shared_ptr<Chord> PercussionUtilities::getDrumNoteForPreview(const Drumset* drumset, int pitch)
56 : {
57 0 : double _spatium = paletteScoreProvider()->paletteScore()->style().spatium(); // TODO: Don't use palette here?
58 :
59 0 : bool up = false;
60 0 : int line = drumset->line(pitch);
61 0 : NoteHeadGroup noteHead = drumset->noteHead(pitch);
62 0 : int voice = drumset->voice(pitch);
63 0 : DirectionV dir = drumset->stemDirection(pitch);
64 :
65 0 : if (dir == DirectionV::UP) {
66 0 : up = true;
67 0 : } else if (dir == DirectionV::DOWN) {
68 0 : up = false;
69 : } else {
70 0 : up = line > 4;
71 : }
72 :
73 0 : auto chord = Factory::makeChord(paletteScoreProvider()->paletteScore()->dummy());
74 0 : chord->setDurationType(DurationType::V_QUARTER);
75 0 : chord->setStemDirection(dir);
76 0 : chord->setIsUiItem(true);
77 0 : chord->setTrack(voice);
78 :
79 0 : Note* note = Factory::createNote(chord.get());
80 0 : note->setMark(true);
81 0 : note->setTrack(voice);
82 0 : note->setPitch(pitch);
83 0 : note->setTpcFromPitch();
84 0 : note->setLine(line);
85 0 : note->setPos(0.0, _spatium * .5 * line);
86 0 : note->setHeadGroup(noteHead);
87 :
88 0 : SymId noteheadSym = SymId::noteheadBlack;
89 0 : if (noteHead == NoteHeadGroup::HEAD_CUSTOM) {
90 0 : noteheadSym = drumset->noteHeads(pitch, NoteHeadType::HEAD_QUARTER);
91 : } else {
92 0 : noteheadSym = note->noteHead(true, noteHead, NoteHeadType::HEAD_QUARTER);
93 : }
94 :
95 0 : note->mutldata()->cachedNoteheadSym.set_value(noteheadSym); // we use the cached notehead so we don't recompute it at each layout
96 0 : chord->add(note);
97 :
98 0 : Stem* stem = Factory::createStem(chord.get());
99 0 : stem->setBaseLength(up ? -3.0_sp : 3.0_sp);
100 0 : engravingRender()->layoutItem(stem);
101 0 : chord->add(stem);
102 :
103 0 : return chord;
104 0 : }
105 :
106 : /// Opens the percussion shortcut dialog, modifies drumset with user input
107 0 : bool PercussionUtilities::editPercussionShortcut(Drumset& drumset, int originPitch)
108 : {
109 0 : IF_ASSERT_FAILED(drumset.isValid(originPitch)) {
110 0 : return false;
111 : }
112 :
113 0 : const muse::RetVal<muse::Val> rv = openPercussionShortcutDialog(drumset, originPitch);
114 0 : if (!rv.ret) {
115 0 : return false;
116 : }
117 :
118 0 : const QVariantMap vals = rv.val.toQVariant().toMap();
119 :
120 0 : drumset.drum(originPitch).shortcut = vals.value("newShortcut").toString();
121 :
122 0 : const int conflictShortcutPitch = vals.value("conflictDrumPitch").toInt();
123 0 : if (drumset.isValid(conflictShortcutPitch)) {
124 0 : drumset.drum(conflictShortcutPitch).shortcut.clear();
125 : }
126 :
127 0 : return true;
128 0 : }
129 :
130 0 : muse::RetVal<muse::Val> PercussionUtilities::openPercussionShortcutDialog(const Drumset& drumset, int originPitch)
131 : {
132 0 : muse::UriQuery query("musescore://notation/editpercussionshortcut?modal=true");
133 :
134 0 : const mu::engraving::DrumInstrument& originDrum = drumset.drum(originPitch);
135 0 : query.addParam("originDrum", muse::Val::fromQVariant(drumToQVariantMap(originPitch, originDrum)));
136 :
137 0 : QVariantList drumsWithShortcut;
138 0 : for (int otherPitch = 0; otherPitch < mu::engraving::DRUM_INSTRUMENTS; ++otherPitch) {
139 0 : if (otherPitch == originPitch || !drumset.isValid(otherPitch) || drumset.shortcut(otherPitch).isEmpty()) {
140 0 : continue;
141 : }
142 0 : QVariantMap drumVariant = drumToQVariantMap(otherPitch, drumset.drum(otherPitch));
143 0 : drumsWithShortcut << drumVariant;
144 0 : }
145 0 : query.addParam("drumsWithShortcut", muse::Val::fromQVariant(drumsWithShortcut));
146 :
147 0 : QVariantList applicationShortcuts;
148 0 : muse::shortcuts::ShortcutList shortcuts = commandShortcutsRegister()->shortcuts();
149 0 : for (const muse::shortcuts::Shortcut& shortcut : shortcuts) {
150 0 : const auto& info = commandsRegister()->commandInfo(shortcut.command);
151 0 : for (const std::string& str : shortcut.sequences) {
152 0 : QVariantMap sc;
153 0 : sc ["title"] = info.title.qTranslatedWithoutMnemonic();
154 0 : sc ["shortcut"] = QString::fromStdString(str);
155 0 : applicationShortcuts << sc;
156 0 : }
157 : }
158 0 : query.addParam("applicationShortcuts", muse::Val::fromQVariant(applicationShortcuts));
159 :
160 0 : return interactive()->openSync(query);
161 0 : }
162 :
163 0 : QVariantMap PercussionUtilities::drumToQVariantMap(int pitch, const engraving::DrumInstrument& drum)
164 : {
165 0 : QVariantMap qv;
166 0 : qv["pitch"] = pitch;
167 0 : qv["title"] = drum.name.toQString();
168 0 : qv["shortcut"] = drum.shortcut.toQString();
169 0 : return qv;
170 0 : }
|