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 "transposedialog.h"
24 :
25 : #include "notation/inotation.h"
26 : #include "notation/inotationinteraction.h"
27 : #include "notation/inotationselection.h"
28 :
29 : #include "ui/view/widgetstatestore.h"
30 :
31 : using namespace mu::notation;
32 : using namespace muse::ui;
33 :
34 : //---------------------------------------------------------
35 : // TransposeDialog
36 : //---------------------------------------------------------
37 :
38 0 : TransposeDialog::TransposeDialog(QWidget* parent)
39 0 : : muse::ui::WidgetDialog(parent)
40 : {
41 0 : setObjectName("TransposeDialog");
42 0 : setupUi(this);
43 0 : setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
44 :
45 0 : connect(transposeByKey, &QGroupBox::clicked, this, &TransposeDialog::transposeByKeyToggled);
46 0 : connect(transposeByInterval, &QGroupBox::clicked, this, &TransposeDialog::transposeByIntervalToggled);
47 0 : connect(chromaticBox, &QGroupBox::clicked, this, &TransposeDialog::chromaticBoxToggled);
48 0 : connect(diatonicBox, &QGroupBox::clicked, this, &TransposeDialog::diatonicBoxToggled);
49 0 : }
50 :
51 0 : void TransposeDialog::componentComplete()
52 : {
53 0 : if (selection()->isNone()) {
54 0 : interaction()->select(SelectionTarget::All);
55 0 : m_allSelected = true;
56 : }
57 :
58 : // TRANSPOSE_TO_KEY and "transpose keys" is only possible if selection state is SelState::RANGE
59 0 : bool rangeSelection = selection()->isRange();
60 0 : setEnableTransposeKeys(rangeSelection);
61 0 : setEnableTransposeToKey(rangeSelection);
62 :
63 0 : const std::vector<EngravingItem*>& elements = selection()->elements();
64 0 : bool hasChordNames = std::any_of(elements.cbegin(), elements.cend(), [](const EngravingItem* item) {
65 0 : return item->isHarmony() || item->isFretDiagram();
66 : });
67 0 : setEnableTransposeChordNames(hasChordNames);
68 :
69 0 : restorePreviousState();
70 :
71 0 : connect(this, &TransposeDialog::accepted, this, &TransposeDialog::apply);
72 :
73 : //! NOTE: It is necessary for the correct start of navigation in the dialog
74 0 : setFocus();
75 0 : }
76 :
77 : //---------------------------------------------------------
78 : // TransposeDialog slots
79 : //---------------------------------------------------------
80 :
81 0 : void TransposeDialog::transposeByKeyToggled(bool val)
82 : {
83 0 : if (val) {
84 0 : transposeByInterval->setChecked(false);
85 : } else {
86 0 : if (!transposeByInterval->isChecked()) {
87 0 : transposeByKey->setChecked(true);
88 : }
89 : }
90 0 : }
91 :
92 0 : void TransposeDialog::transposeByIntervalToggled(bool val)
93 : {
94 0 : if (val) {
95 0 : transposeByKey->setChecked(false);
96 : } else {
97 0 : if (!transposeByKey->isChecked()) {
98 0 : transposeByInterval->setChecked(true);
99 : }
100 : }
101 0 : }
102 :
103 0 : void TransposeDialog::chromaticBoxToggled(bool val)
104 : {
105 0 : if (val) {
106 0 : diatonicBox->setChecked(false);
107 : } else {
108 0 : if (!diatonicBox->isChecked()) {
109 0 : chromaticBox->setChecked(true);
110 : }
111 : }
112 0 : }
113 :
114 0 : void TransposeDialog::diatonicBoxToggled(bool val)
115 : {
116 0 : if (val) {
117 0 : chromaticBox->setChecked(false);
118 : } else {
119 0 : if (!chromaticBox->isChecked()) {
120 0 : diatonicBox->setChecked(true);
121 : }
122 : }
123 0 : }
124 :
125 : //---------------------------------------------------------
126 : // mode
127 : //---------------------------------------------------------
128 :
129 0 : TransposeMode TransposeDialog::mode() const
130 : {
131 0 : return chromaticBox->isChecked()
132 0 : ? (transposeByKey->isChecked() ? TransposeMode::TO_KEY : TransposeMode::BY_INTERVAL)
133 0 : : TransposeMode::DIATONICALLY;
134 : }
135 :
136 : //---------------------------------------------------------
137 : // enableTransposeByKey
138 : //---------------------------------------------------------
139 :
140 0 : void TransposeDialog::setEnableTransposeToKey(bool val)
141 : {
142 0 : transposeByKey->setEnabled(val);
143 0 : transposeByInterval->setChecked(!val);
144 0 : transposeByKey->setChecked(val);
145 0 : }
146 :
147 : //---------------------------------------------------------
148 : // enableTransposeChordNames
149 : //---------------------------------------------------------
150 :
151 0 : void TransposeDialog::setEnableTransposeChordNames(bool val)
152 : {
153 0 : transposeChordNames->setEnabled(val);
154 0 : }
155 :
156 : //---------------------------------------------------------
157 : // direction
158 : //---------------------------------------------------------
159 :
160 0 : TransposeDirection TransposeDialog::direction() const
161 : {
162 0 : switch (mode()) {
163 0 : case TransposeMode::TO_KEY:
164 0 : if (closestKey->isChecked()) {
165 0 : return TransposeDirection::CLOSEST;
166 : }
167 0 : return upKey->isChecked() ? TransposeDirection::UP : TransposeDirection::DOWN;
168 0 : case TransposeMode::BY_INTERVAL:
169 0 : return upInterval->isChecked() ? TransposeDirection::UP : TransposeDirection::DOWN;
170 0 : case TransposeMode::DIATONICALLY:
171 0 : return upDiatonic->isChecked() ? TransposeDirection::UP : TransposeDirection::DOWN;
172 0 : case TransposeMode::UNKNOWN:
173 0 : return TransposeDirection::UNKNOWN;
174 : }
175 0 : return TransposeDirection::UP;
176 : }
177 :
178 : //---------------------------------------------------------
179 : // showEvent
180 : //---------------------------------------------------------
181 :
182 0 : void TransposeDialog::showEvent(QShowEvent* event)
183 : {
184 0 : WidgetStateStore::restoreGeometry(this);
185 0 : QDialog::showEvent(event);
186 0 : }
187 :
188 : //---------------------------------------------------------
189 : // hideEvent
190 : //---------------------------------------------------------
191 :
192 0 : void TransposeDialog::hideEvent(QHideEvent* event)
193 : {
194 0 : WidgetStateStore::saveGeometry(this);
195 0 : QWidget::hideEvent(event);
196 0 : }
197 :
198 0 : INotationPtr TransposeDialog::notation() const
199 : {
200 0 : return context()->currentNotation();
201 : }
202 :
203 0 : INotationInteractionPtr TransposeDialog::interaction() const
204 : {
205 0 : return notation()->interaction();
206 : }
207 :
208 0 : INotationSelectionPtr TransposeDialog::selection() const
209 : {
210 0 : return interaction()->selection();
211 : }
212 :
213 0 : void TransposeDialog::apply()
214 : {
215 0 : TransposeOptions options;
216 0 : options.mode = mode();
217 0 : options.direction = direction();
218 0 : options.key = transposeKey();
219 0 : options.interval = transposeInterval();
220 0 : options.needTransposeKeys = getTransposeKeys();
221 0 : options.needTransposeChordNames = getTransposeChordNames();
222 0 : options.needTransposeDoubleSharpsFlats = useDoubleSharpsFlats();
223 :
224 0 : saveState();
225 :
226 0 : interaction()->transpose(options);
227 :
228 0 : if (m_allSelected) {
229 0 : interaction()->clearSelection();
230 : }
231 0 : }
232 :
233 0 : void TransposeDialog::setEnableTransposeKeys(bool val)
234 : {
235 0 : transposeKeys->setEnabled(val);
236 0 : }
237 :
238 0 : bool TransposeDialog::getTransposeKeys() const
239 : {
240 0 : return chromaticBox->isChecked()
241 0 : ? transposeKeys->isChecked()
242 0 : : keepDegreeAlterations->isChecked();
243 : }
244 :
245 0 : bool TransposeDialog::getTransposeChordNames() const
246 : {
247 0 : return transposeChordNames->isChecked();
248 : }
249 :
250 0 : Key TransposeDialog::transposeKey() const
251 : {
252 0 : return Key(keyList->currentIndex() - 7);
253 : }
254 :
255 0 : int TransposeDialog::transposeInterval() const
256 : {
257 0 : return chromaticBox->isChecked()
258 0 : ? intervalList->currentIndex()
259 0 : : degreeList->currentIndex() + 1;
260 : }
261 :
262 0 : bool TransposeDialog::useDoubleSharpsFlats() const
263 : {
264 0 : return accidentalOptions->currentIndex() == 1;
265 : }
266 :
267 0 : TransposeDialogState& TransposeDialog::previousState()
268 : {
269 : static TransposeDialogState options;
270 0 : return options;
271 : }
272 :
273 0 : void TransposeDialog::restorePreviousState()
274 : {
275 0 : const TransposeDialogState& state = previousState();
276 :
277 0 : chromaticBox->setChecked(state.chromaticChecked);
278 0 : diatonicBox->setChecked(!state.chromaticChecked);
279 :
280 0 : transposeByKey->setChecked(state.transposeByKeyChecked);
281 0 : transposeByInterval->setChecked(!state.transposeByKeyChecked);
282 :
283 0 : keyList->setCurrentIndex(state.keyListIdx);
284 0 : closestKey->setChecked(state.closestKeyChecked);
285 0 : upKey->setChecked(state.upKeyChecked);
286 0 : downKey->setChecked(!state.closestKeyChecked && !state.upKeyChecked);
287 :
288 0 : intervalList->setCurrentIndex(state.chromaticIntervalIdx);
289 0 : upInterval->setChecked(state.upIntervalChecked);
290 0 : downInterval->setChecked(!state.upIntervalChecked);
291 :
292 0 : transposeKeys->setChecked(state.needTransposeKeysChecked);
293 :
294 0 : degreeList->setCurrentIndex(state.diatonicIntervalIdx);
295 0 : upDiatonic->setChecked(state.upDiatonicChecked);
296 0 : downDiatonic->setChecked(!state.upDiatonicChecked);
297 0 : keepDegreeAlterations->setChecked(state.keepDegreeAlterationsChecked);
298 :
299 0 : transposeChordNames->setChecked(state.needTransposeChordNamesChecked);
300 0 : accidentalOptions->setCurrentIndex(state.needTransposeDoubleSharpsFlatsIdx);
301 0 : }
302 :
303 0 : void TransposeDialog::saveState()
304 : {
305 0 : TransposeDialogState& state = previousState();
306 :
307 0 : state.chromaticChecked = chromaticBox->isChecked();
308 0 : state.transposeByKeyChecked = transposeByKey->isChecked();
309 0 : state.closestKeyChecked = closestKey->isChecked();
310 0 : state.upKeyChecked = upKey->isChecked();
311 0 : state.keyListIdx = keyList->currentIndex();
312 0 : state.upIntervalChecked = upInterval->isChecked();
313 0 : state.chromaticIntervalIdx = intervalList->currentIndex();
314 0 : state.upDiatonicChecked = upDiatonic->isChecked();
315 0 : state.diatonicIntervalIdx = degreeList->currentIndex();
316 0 : state.keepDegreeAlterationsChecked = keepDegreeAlterations->isChecked();
317 0 : state.needTransposeKeysChecked = transposeKeys->isChecked();
318 0 : state.needTransposeChordNamesChecked = transposeChordNames->isChecked();
319 0 : state.needTransposeDoubleSharpsFlatsIdx = accidentalOptions->currentIndex();
320 0 : }
|