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) 2021 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 "noteGroups.h"
24 :
25 : #include "engraving/dom/chord.h"
26 : #include "engraving/dom/mcursor.h"
27 : #include "engraving/dom/timesig.h"
28 : #include "engraving/dom/masterscore.h"
29 : #include "engraving/dom/part.h"
30 : #include "engraving/dom/key.h"
31 : #include "engraving/dom/actionicon.h"
32 : #include "engraving/dom/staff.h"
33 :
34 : #include "translation.h"
35 :
36 : using namespace mu::palette;
37 : using namespace mu::engraving;
38 :
39 0 : Score* NoteGroups::createScore(int n, DurationType t, std::vector<Chord*>* chords)
40 : {
41 0 : MCursor c;
42 0 : c.setTimeSig(_sig);
43 0 : c.createScore(iocContext(), u"");
44 0 : c.addPart(u"voice");
45 0 : c.move(0, Fraction(0, 1));
46 0 : c.addKeySig(Key::C);
47 :
48 0 : TimeSig* nts = c.addTimeSig(_sig);
49 0 : if (!_z.isEmpty()) {
50 0 : nts->setNumeratorString(_z);
51 : }
52 0 : if (!_n.isEmpty()) {
53 0 : nts->setDenominatorString(_n);
54 : }
55 0 : GroupNode node { 0, 0 };
56 0 : Groups ng;
57 0 : ng.addNode(node);
58 0 : nts->setGroups(ng);
59 :
60 0 : for (int i = 0; i < n; ++i) {
61 0 : Chord* chord = c.addChord(77, t);
62 0 : Fraction tick = chord->rtick();
63 0 : chord->setBeamMode(_groups.beamMode(tick.ticks(), t));
64 0 : chord->setStemDirection(DirectionV::UP);
65 0 : chords->push_back(chord);
66 : }
67 :
68 0 : c.score()->style().set(Sid::pageOddLeftMargin, 0.0);
69 0 : c.score()->style().set(Sid::pageOddTopMargin, 10.0 / INCH);
70 0 : c.score()->style().set(Sid::startBarlineSingle, true);
71 :
72 0 : StaffType* st = c.score()->staff(0)->staffType(Fraction(0, 1));
73 0 : st->setLines(1); // single line only
74 0 : st->setGenClef(false); // no clef
75 : // st->setGenTimesig(false); // don't display time sig since NoteGroupsExampleView is unable to reflect custom time sig text/symbols
76 :
77 0 : return c.score();
78 0 : }
79 :
80 0 : NoteGroups::NoteGroups(QWidget* parent)
81 0 : : QGroupBox(parent), muse::Contextable(muse::iocCtxForQWidget(this))
82 : {
83 0 : setupUi(this);
84 0 : }
85 :
86 0 : void NoteGroups::classBegin()
87 : {
88 0 : iconPalette->setIocContext();
89 :
90 0 : iconPalette->setName(QT_TRANSLATE_NOOP("palette", "Beam selector"));
91 0 : iconPalette->setGridSize(27, 40);
92 0 : iconPalette->setDrawGrid(true);
93 :
94 0 : iconPalette->appendActionIcon(ActionIconType::BEAM_JOIN);
95 0 : iconPalette->appendActionIcon(ActionIconType::BEAM_BREAK_LEFT);
96 0 : iconPalette->appendActionIcon(ActionIconType::BEAM_BREAK_INNER_8TH);
97 0 : iconPalette->appendActionIcon(ActionIconType::BEAM_BREAK_INNER_16TH);
98 :
99 0 : iconPalette->setReadOnly(true);
100 0 : iconPalette->setApplyingElementsDisabled(true);
101 0 : iconPalette->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
102 0 : iconPalette->setFixedHeight(iconPalette->heightForWidth(iconPalette->width()));
103 0 : iconPalette->setMinimumWidth(27 * 4 * paletteConfiguration()->paletteScaling() + 1); // enough room for all icons, with roundoff
104 0 : iconPalette->updateGeometry();
105 :
106 0 : connect(resetGroups, &QPushButton::clicked, this, &NoteGroups::resetClicked);
107 :
108 0 : connect(view8, &NoteGroupsExampleView::noteClicked, this, &NoteGroups::noteClicked);
109 0 : connect(view16, &NoteGroupsExampleView::noteClicked, this, &NoteGroups::noteClicked);
110 0 : connect(view32, &NoteGroupsExampleView::noteClicked, this, &NoteGroups::noteClicked);
111 :
112 0 : connect(view8, &NoteGroupsExampleView::beamPropertyDropped, this, &NoteGroups::beamPropertyDropped);
113 0 : connect(view16, &NoteGroupsExampleView::beamPropertyDropped, this, &NoteGroups::beamPropertyDropped);
114 0 : connect(view32, &NoteGroupsExampleView::beamPropertyDropped, this, &NoteGroups::beamPropertyDropped);
115 0 : }
116 :
117 0 : void NoteGroups::setSig(Fraction sig, const Groups& g, const QString& z, const QString& n)
118 : {
119 0 : _sig = sig;
120 0 : _z = z;
121 0 : _n = n;
122 0 : _groups = g;
123 0 : chords8.clear();
124 0 : chords16.clear();
125 0 : chords32.clear();
126 0 : Fraction f = _sig.reduced();
127 0 : int nn = f.numerator() * (8 / f.denominator());
128 0 : view8->setScore(createScore(nn, DurationType::V_EIGHTH, &chords8));
129 0 : nn = f.numerator() * (16 / f.denominator());
130 0 : view16->setScore(createScore(nn, DurationType::V_16TH, &chords16));
131 0 : nn = f.numerator() * (32 / f.denominator());
132 0 : view32->setScore(createScore(nn, DurationType::V_32ND, &chords32));
133 0 : }
134 :
135 0 : Groups NoteGroups::groups()
136 : {
137 0 : Groups g;
138 0 : for (Chord* chord : chords8) {
139 0 : g.addStop(chord->rtick().ticks(), chord->durationType().type(), chord->beamMode());
140 : }
141 0 : for (Chord* chord : chords16) {
142 0 : g.addStop(chord->rtick().ticks(), chord->durationType().type(), chord->beamMode());
143 : }
144 0 : for (Chord* chord : chords32) {
145 0 : g.addStop(chord->rtick().ticks(), chord->durationType().type(), chord->beamMode());
146 : }
147 0 : return g;
148 0 : }
149 :
150 0 : void NoteGroups::resetClicked()
151 : {
152 0 : setSig(_sig, _groups, _z, _n);
153 0 : }
154 :
155 0 : void NoteGroups::noteClicked(Note* note)
156 : {
157 0 : Chord* chord = note->chord();
158 0 : if (chord->beamMode() == BeamMode::AUTO) {
159 0 : updateBeams(chord, BeamMode::BEGIN);
160 : } else {
161 0 : updateBeams(chord, BeamMode::AUTO);
162 : }
163 0 : }
164 :
165 0 : void NoteGroups::beamPropertyDropped(Chord* chord, ActionIcon* icon)
166 : {
167 0 : switch (icon->actionType()) {
168 0 : case ActionIconType::BEAM_JOIN:
169 0 : updateBeams(chord, BeamMode::AUTO);
170 0 : break;
171 0 : case ActionIconType::BEAM_BREAK_LEFT:
172 0 : updateBeams(chord, BeamMode::BEGIN);
173 0 : break;
174 0 : case ActionIconType::BEAM_BREAK_INNER_8TH:
175 0 : updateBeams(chord, BeamMode::BEGIN16);
176 0 : break;
177 0 : case ActionIconType::BEAM_BREAK_INNER_16TH:
178 0 : updateBeams(chord, BeamMode::BEGIN32);
179 0 : break;
180 0 : default:
181 0 : break;
182 : }
183 0 : }
184 :
185 : /// takes into account current state of changeShorterCheckBox to update smaller valued notes as well
186 0 : void NoteGroups::updateBeams(Chord* chord, BeamMode m)
187 : {
188 0 : chord->setBeamMode(m);
189 0 : chord->score()->doLayout();
190 :
191 0 : if (changeShorterCheckBox->checkState() == Qt::Checked) {
192 0 : Fraction tick = chord->tick();
193 0 : bool foundChord = false;
194 0 : for (Chord* c : chords8) {
195 0 : if (c == chord) {
196 0 : foundChord = true;
197 0 : break;
198 : }
199 : }
200 0 : for (Chord* c : chords16) {
201 0 : if (foundChord) {
202 0 : if (c->tick() == tick) {
203 0 : c->setBeamMode(m);
204 0 : c->score()->doLayout();
205 0 : break;
206 : }
207 0 : } else if (c == chord) {
208 0 : foundChord = true;
209 0 : break;
210 : }
211 : }
212 0 : for (Chord* c : chords32) {
213 0 : if (foundChord) {
214 0 : if (c->tick() == tick) {
215 0 : c->setBeamMode(m);
216 0 : c->score()->doLayout();
217 0 : break;
218 : }
219 : }
220 : }
221 : }
222 :
223 0 : view8->update();
224 0 : view16->update();
225 0 : view32->update();
226 0 : }
|