1 //=============================================================================
2 // MuseScore
3 // Linux Music Score Editor
4 //
5 // Copyright (C) 2002-2007 Werner Schweer and others
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19
20 #include "editdrumset.h"
21 #include "menus.h"
22 #include "musescore.h"
23 #include "libmscore/xml.h"
24 #include "libmscore/utils.h"
25 #include "libmscore/chord.h"
26 #include "libmscore/score.h"
27 #include "libmscore/note.h"
28 #include "libmscore/stem.h"
29
30 namespace Ms {
31
32 enum Column : char { PITCH, NOTE, SHORTCUT, NAME };
33
34 //---------------------------------------------------------
35 // noteHeadNames
36 // "Sol" and "Alt. Brevis" omitted,
37 // as not being useful for drums
38 //---------------------------------------------------------
39
40 NoteHead::Group noteHeadNames[] = {
41 NoteHead::Group::HEAD_NORMAL,
42 NoteHead::Group::HEAD_CROSS,
43 NoteHead::Group::HEAD_PLUS,
44 NoteHead::Group::HEAD_XCIRCLE,
45 NoteHead::Group::HEAD_WITHX,
46 NoteHead::Group::HEAD_TRIANGLE_UP,
47 NoteHead::Group::HEAD_TRIANGLE_DOWN,
48 NoteHead::Group::HEAD_SLASH,
49 NoteHead::Group::HEAD_SLASHED1,
50 NoteHead::Group::HEAD_SLASHED2,
51 NoteHead::Group::HEAD_DIAMOND,
52 NoteHead::Group::HEAD_DIAMOND_OLD,
53 NoteHead::Group::HEAD_CIRCLED,
54 NoteHead::Group::HEAD_CIRCLED_LARGE,
55 NoteHead::Group::HEAD_LARGE_ARROW,
56 NoteHead::Group::HEAD_DO,
57 NoteHead::Group::HEAD_RE,
58 NoteHead::Group::HEAD_MI,
59 NoteHead::Group::HEAD_FA,
60 NoteHead::Group::HEAD_LA,
61 NoteHead::Group::HEAD_TI,
62 NoteHead::Group::HEAD_CUSTOM
63 };
64
65 //---------------------------------------------------------
66 // operator<
67 //---------------------------------------------------------
68
operator <(const QTreeWidgetItem & other) const69 bool EditDrumsetTreeWidgetItem::operator<(const QTreeWidgetItem & other) const
70 {
71 if (treeWidget()->sortColumn() == Column::PITCH)
72 return data(Column::PITCH, Qt::UserRole).toInt() < other.data(Column::PITCH, Qt::UserRole).toInt();
73 else
74 return QTreeWidgetItem::operator<(other);
75 }
76
77 //---------------------------------------------------------
78 // EditDrumset
79 //---------------------------------------------------------
80
81 struct SymbolIcon {
82 SymId id;
83 QIcon icon;
SymbolIconMs::SymbolIcon84 SymbolIcon(SymId i, QIcon j)
85 : id(i), icon(j)
86 {}
87
generateIconMs::SymbolIcon88 static SymbolIcon generateIcon(const SymId& id, double w, double h, double defaultScale)
89 {
90 QIcon icon;
91 QPixmap image(w, h);
92 image.fill(Qt::transparent);
93 QPainter painter(&image);
94 const QRectF& bbox = ScoreFont::fallbackFont()->bbox(id, 1);
95 const qreal actualSymbolScale = std::min(w / bbox.width(), h / bbox.height());
96 qreal mag = std::min(defaultScale, actualSymbolScale);
97 const qreal& xStShift = (w - mag * bbox.width()) / 2 - mag*bbox.left();
98 const qreal& yStShift = (h - mag * bbox.height()) / 2 - mag*bbox.top();
99 const QPointF& stPtPos = QPointF(xStShift, yStShift);
100 ScoreFont::fallbackFont()->draw(id, &painter, mag, stPtPos);
101 painter.end();
102 icon.addPixmap(image);
103 return SymbolIcon(id, icon);
104 }
105 };
106
EditDrumset(const Drumset * ds,QWidget * parent)107 EditDrumset::EditDrumset(const Drumset* ds, QWidget* parent)
108 : QDialog(parent)
109 {
110 setObjectName("EditDrumset");
111
112 nDrumset = *ds;
113 setupUi(this);
114 setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
115
116 drumNote->setGrid(70, 80);
117 drumNote->setDrawGrid(false);
118 drumNote->setReadOnly(true);
119
120 updatePitchesList();
121
122 for (auto g : noteHeadNames)
123 noteHead->addItem(NoteHead::group2userName(g), int(g));
124
125 connect(pitchList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
126 SLOT(itemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
127 connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(bboxClicked(QAbstractButton*)));
128 connect(name, SIGNAL(textChanged(const QString&)), SLOT(nameChanged(const QString&)));
129 connect(noteHead, SIGNAL(currentIndexChanged(int)), SLOT(valueChanged()));
130 connect(staffLine, SIGNAL(valueChanged(int)), SLOT(valueChanged()));
131 connect(voice, SIGNAL(currentIndexChanged(int)), SLOT(valueChanged()));
132 connect(stemDirection, SIGNAL(currentIndexChanged(int)), SLOT(valueChanged()));
133 connect(shortcut, SIGNAL(currentIndexChanged(int)), SLOT(shortcutChanged()));
134 connect(loadButton, SIGNAL(clicked()), SLOT(load()));
135 connect(saveButton, SIGNAL(clicked()), SLOT(save()));
136 pitchList->setColumnWidth(0, 40);
137 pitchList->setColumnWidth(1, 60);
138 pitchList->setColumnWidth(2, 30);
139
140 QStringList validNoteheadRanges = { "Noteheads", "Round and square noteheads", "Slash noteheads", "Shape note noteheads", "Shape note noteheads supplement" };
141 QSet<QString> excludeSym = {"noteheadParenthesisLeft", "noteheadParenthesisRight", "noteheadParenthesis", "noteheadNull"};
142 QStringList primaryNoteheads = {
143 "noteheadXOrnate",
144 "noteheadXBlack",
145 "noteheadXHalf",
146 "noteheadXWhole",
147 "noteheadXDoubleWhole",
148 "noteheadSlashedBlack1",
149 "noteheadSlashedHalf1",
150 "noteheadSlashedWhole1",
151 "noteheadSlashedDoubleWhole1",
152 "noteheadSlashedBlack2",
153 "noteheadSlashedHalf2",
154 "noteheadSlashedWhole2",
155 "noteheadSlashedDoubleWhole2",
156 "noteheadSquareBlack",
157 "noteheadMoonBlack",
158 "noteheadTriangleUpRightBlack",
159 "noteheadTriangleDownBlack",
160 "noteheadTriangleUpBlack",
161 "noteheadTriangleLeftBlack",
162 "noteheadTriangleRoundDownBlack",
163 "noteheadDiamondBlack",
164 "noteheadDiamondHalf",
165 "noteheadDiamondWhole",
166 "noteheadDiamondDoubleWhole",
167 "noteheadRoundWhiteWithDot",
168 "noteheadVoidWithX",
169 "noteheadHalfWithX",
170 "noteheadWholeWithX",
171 "noteheadDoubleWholeWithX",
172 "noteheadLargeArrowUpBlack",
173 "noteheadLargeArrowUpHalf",
174 "noteheadLargeArrowUpWhole",
175 "noteheadLargeArrowUpDoubleWhole"
176 };
177
178 int w = quarterCmb->iconSize().width() * qApp->devicePixelRatio();
179 int h = quarterCmb->iconSize().height() * qApp->devicePixelRatio();
180 //default scale is 0.3, will use smaller scale for large noteheads symbols
181 const qreal defaultScale = 0.3 * qApp->devicePixelRatio();
182
183 QList<SymbolIcon> resNoteheads;
184 for (auto symName : primaryNoteheads) {
185 SymId id = Sym::name2id(symName);
186 resNoteheads.append(SymbolIcon::generateIcon(id, w, h, defaultScale));
187 }
188
189 for (QString range : validNoteheadRanges) {
190 for (auto symName : (*smuflRanges())[range]) {
191 SymId id = Sym::name2id(symName);
192 if (!excludeSym.contains(symName) && !primaryNoteheads.contains(symName))
193 resNoteheads.append(SymbolIcon::generateIcon(id, w, h, defaultScale));
194 }
195 }
196
197 QComboBox* combos[] = { wholeCmb, halfCmb, quarterCmb, doubleWholeCmb };
198 for (QComboBox* combo : combos) {
199 for (auto si : resNoteheads) {
200 SymId id = si.id;
201 QIcon icon = si.icon;
202 combo->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
203 combo->addItem(icon, Sym::id2userName(id), Sym::id2name(id));
204 }
205 }
206 wholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(SymId::noteheadWhole)));
207 halfCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(SymId::noteheadHalf)));
208 quarterCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(SymId::noteheadBlack)));
209 doubleWholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(SymId::noteheadDoubleWhole)));
210
211 connect(customGbox, SIGNAL(toggled(bool)), this, SLOT(customGboxToggled(bool)));
212 connect(quarterCmb, SIGNAL(currentIndexChanged(int)), SLOT(customQuarterChanged(int)));
213
214 MuseScore::restoreGeometry(this);
215
216 Q_ASSERT(pitchList->topLevelItemCount() > 0);
217 pitchList->setCurrentItem(pitchList->topLevelItem(0));
218 pitchList->setFocus();
219 }
220
221 //---------------------------------------------------------
222 // customGboxToggled
223 //---------------------------------------------------------
224
customGboxToggled(bool checked)225 void EditDrumset::customGboxToggled(bool checked) {
226 noteHead->setEnabled(!checked);
227 if (checked)
228 noteHead->setCurrentIndex(noteHead->findData(int(NoteHead::Group::HEAD_CUSTOM)));
229 else
230 noteHead->setCurrentIndex(noteHead->findData(int(NoteHead::Group::HEAD_NORMAL)));
231 }
232
233 //---------------------------------------------------------
234 // updatePitchesList
235 //---------------------------------------------------------
236
updatePitchesList()237 void EditDrumset::updatePitchesList()
238 {
239 pitchList->clear();
240 for (int i = 0; i < 128; ++i) {
241 QTreeWidgetItem* item = new EditDrumsetTreeWidgetItem(pitchList);
242 item->setText(Column::PITCH, QString("%1").arg(i));
243 item->setText(Column::NOTE, pitch2string(i));
244 if (nDrumset.shortcut(i) == 0)
245 item->setText(Column::SHORTCUT, "");
246 else {
247 QString s(QChar(nDrumset.shortcut(i)));
248 item->setText(Column::SHORTCUT, s);
249 }
250 item->setText(Column::NAME, qApp->translate("drumset", nDrumset.name(i).toUtf8().constData()));
251 item->setData(Column::PITCH, Qt::UserRole, i);
252 }
253 pitchList->sortItems(3, Qt::SortOrder::DescendingOrder);
254 }
255
256 //---------------------------------------------------------
257 // refreshPitchesList
258 //---------------------------------------------------------
refreshPitchesList()259 void EditDrumset::refreshPitchesList()
260 {
261 for (int i = 0; i < pitchList->topLevelItemCount(); ++i) {
262 QTreeWidgetItem* item = pitchList->topLevelItem(i);
263 int pitch = item->data(0, Qt::UserRole).toInt();
264 if (nDrumset.shortcut(pitch) == 0)
265 item->setText(Column::SHORTCUT, "");
266 else {
267 QString s(QChar(nDrumset.shortcut(pitch)));
268 item->setText(Column::SHORTCUT, s);
269 }
270 item->setText(Column::NAME, qApp->translate("drumset", nDrumset.name(pitch).toUtf8().constData()));
271 item->setData(0, Qt::UserRole, pitch);
272 }
273 }
274
setEnabledPitchControls(bool enable)275 void EditDrumset::setEnabledPitchControls(bool enable)
276 {
277 customGbox->setEnabled(enable);
278 noteHead->setEnabled(enable);
279 voice->setEnabled(enable);
280 shortcut->setEnabled(enable);
281 staffLine->setEnabled(enable);
282 stemDirection->setEnabled(enable);
283 drumNote->setEnabled(enable);
284 label_2->setEnabled(enable);
285 label_3->setEnabled(enable);
286 label_4->setEnabled(enable);
287 label_5->setEnabled(enable);
288 label_6->setEnabled(enable);
289 }
290
291 //---------------------------------------------------------
292 // nameChanged
293 //---------------------------------------------------------
294
nameChanged(const QString & n)295 void EditDrumset::nameChanged(const QString& n)
296 {
297 QTreeWidgetItem* item = pitchList->currentItem();
298 if (item) {
299 item->setText(Column::NAME, n);
300 int pitch = item->data(Column::PITCH, Qt::UserRole).toInt();
301 if (!n.isEmpty()) {
302 if (!nDrumset.isValid(pitch))
303 noteHead->setCurrentIndex(0);
304 }
305 else
306 nDrumset.drum(pitch).name.clear();
307 }
308 setEnabledPitchControls(!n.isEmpty());
309 }
310
311 //---------------------------------------------------------
312 // shortcutChanged
313 //---------------------------------------------------------
314
shortcutChanged()315 void EditDrumset::shortcutChanged()
316 {
317 QTreeWidgetItem* item = pitchList->currentItem();
318 if (!item)
319 return;
320
321 int pitch = item->data(Column::PITCH, Qt::UserRole).toInt();
322 int sc;
323 if (shortcut->currentIndex() == 7)
324 sc = 0;
325 else
326 sc = "ABCDEFG"[shortcut->currentIndex()];
327
328 if (QString(QChar(nDrumset.drum(pitch).shortcut)) != shortcut->currentText()) {
329 //
330 // remove conflicting shortcuts
331 //
332 for (int i = 0; i < DRUM_INSTRUMENTS; ++i) {
333 if (i == pitch)
334 continue;
335 if (nDrumset.drum(i).shortcut == sc)
336 nDrumset.drum(i).shortcut = 0;
337 }
338 nDrumset.drum(pitch).shortcut = sc;
339 if (shortcut->currentIndex() == 7)
340 item->setText(Column::SHORTCUT, "");
341 else
342 item->setText(Column::SHORTCUT, shortcut->currentText());
343 }
344 refreshPitchesList();
345 }
346
347 //---------------------------------------------------------
348 // bboxClicked
349 //---------------------------------------------------------
bboxClicked(QAbstractButton * button)350 void EditDrumset::bboxClicked(QAbstractButton* button)
351 {
352 QDialogButtonBox::ButtonRole br = buttonBox->buttonRole(button);
353 switch(br) {
354 case QDialogButtonBox::ApplyRole:
355 apply();
356 break;
357
358 case QDialogButtonBox::AcceptRole:
359 apply();
360 // fall through
361
362 case QDialogButtonBox::RejectRole:
363 close();
364 break;
365
366 default:
367 qDebug("EditDrumSet: unknown button");
368 break;
369 }
370 }
371
372 //---------------------------------------------------------
373 // apply
374 //---------------------------------------------------------
apply()375 void EditDrumset::apply()
376 {
377 valueChanged(); //save last changes in name
378 }
379
380 //---------------------------------------------------------
381 // fillCustomNoteheadsDataFromComboboxes
382 //---------------------------------------------------------
fillCustomNoteheadsDataFromComboboxes(int pitch)383 void EditDrumset::fillCustomNoteheadsDataFromComboboxes(int pitch)
384 {
385 nDrumset.drum(pitch).notehead = NoteHead::Group::HEAD_CUSTOM;
386 nDrumset.drum(pitch).noteheads[int(NoteHead::Type::HEAD_WHOLE)] = Sym::name2id(wholeCmb->currentData().toString());
387 nDrumset.drum(pitch).noteheads[int(NoteHead::Type::HEAD_QUARTER)] = Sym::name2id(quarterCmb->currentData().toString());
388 nDrumset.drum(pitch).noteheads[int(NoteHead::Type::HEAD_HALF)] = Sym::name2id(halfCmb->currentData().toString());
389 nDrumset.drum(pitch).noteheads[int(NoteHead::Type::HEAD_BREVIS)] = Sym::name2id(doubleWholeCmb->currentData().toString());
390 }
391
fillNoteheadsComboboxes(bool customGroup,int pitch)392 void EditDrumset::fillNoteheadsComboboxes(bool customGroup, int pitch)
393 {
394 if (customGroup) {
395 wholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(nDrumset.noteHeads(pitch, NoteHead::Type::HEAD_WHOLE))));
396 halfCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(nDrumset.noteHeads(pitch, NoteHead::Type::HEAD_HALF))));
397 quarterCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(nDrumset.noteHeads(pitch, NoteHead::Type::HEAD_QUARTER))));
398 doubleWholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(nDrumset.noteHeads(pitch, NoteHead::Type::HEAD_BREVIS))));
399 }
400 else {
401 const auto group = nDrumset.drum(pitch).notehead;
402 if (group == NoteHead::Group::HEAD_INVALID)
403 return;
404
405 wholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(Note::noteHead(0, group, NoteHead::Type::HEAD_WHOLE))));
406 halfCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(Note::noteHead(0, group, NoteHead::Type::HEAD_HALF))));
407 quarterCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(Note::noteHead(0, group, NoteHead::Type::HEAD_QUARTER))));
408 doubleWholeCmb->setCurrentIndex(quarterCmb->findData(Sym::id2name(Note::noteHead(0, group, NoteHead::Type::HEAD_BREVIS))));
409 }
410 }
411
412 //---------------------------------------------------------
413 // itemChanged
414 //---------------------------------------------------------
itemChanged(QTreeWidgetItem * current,QTreeWidgetItem * previous)415 void EditDrumset::itemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
416 {
417 if (previous) {
418 int pitch = previous->data(0, Qt::UserRole).toInt();
419 nDrumset.drum(pitch).name = name->text();
420 if (customGbox->isChecked())
421 fillCustomNoteheadsDataFromComboboxes(pitch);
422 else {
423 const QVariant currData = noteHead->currentData();
424 if (currData.isValid())
425 nDrumset.drum(pitch).notehead = NoteHead::Group(currData.toInt());
426 }
427
428 nDrumset.drum(pitch).line = staffLine->value();
429 nDrumset.drum(pitch).voice = voice->currentIndex();
430 if (shortcut->currentIndex() == 7)
431 nDrumset.drum(pitch).shortcut = 0;
432 else
433 nDrumset.drum(pitch).shortcut = "ABCDEFG"[shortcut->currentIndex()];
434 nDrumset.drum(pitch).stemDirection = Direction(stemDirection->currentIndex());
435 previous->setText(Column::NAME, qApp->translate("drumset", nDrumset.name(pitch).toUtf8().constData()));
436 }
437 if (current == 0)
438 return;
439
440 staffLine->blockSignals(true);
441 voice->blockSignals(true);
442 stemDirection->blockSignals(true);
443 noteHead->blockSignals(true);
444
445 int pitch = current->data(0, Qt::UserRole).toInt();
446 name->setText(qApp->translate("drumset", nDrumset.name(pitch).toUtf8().constData()));
447 staffLine->setValue(nDrumset.line(pitch));
448 qDebug("BEFORE %d", nDrumset.voice(pitch));
449 voice->setCurrentIndex(nDrumset.voice(pitch));
450 qDebug("AFTER %d", nDrumset.voice(pitch));
451 stemDirection->setCurrentIndex(int(nDrumset.stemDirection(pitch)));
452
453 NoteHead::Group nh = nDrumset.noteHead(pitch);
454 bool isCustomGroup = (nh == NoteHead::Group::HEAD_CUSTOM);
455 if (nDrumset.isValid(pitch))
456 setCustomNoteheadsGUIEnabled(isCustomGroup);
457 noteHead->setCurrentIndex(noteHead->findData(int(nh)));
458 fillNoteheadsComboboxes(isCustomGroup, pitch);
459
460 if (nDrumset.shortcut(pitch) == 0)
461 shortcut->setCurrentIndex(7);
462 else
463 shortcut->setCurrentIndex(nDrumset.shortcut(pitch) - 'A');
464
465 staffLine->blockSignals(false);
466 voice->blockSignals(false);
467 stemDirection->blockSignals(false);
468 noteHead->blockSignals(false);
469
470 updateExample();
471 }
472
473 //---------------------------------------------------------
474 // setCustomNoteheadsGUIEnabled
475 //---------------------------------------------------------
setCustomNoteheadsGUIEnabled(bool enabled)476 void EditDrumset::setCustomNoteheadsGUIEnabled(bool enabled)
477 {
478 customGbox->setChecked(enabled);
479 noteHead->setEnabled(!enabled);
480 if (enabled)
481 noteHead->setCurrentIndex(noteHead->findData(int(NoteHead::Group::HEAD_CUSTOM)));
482 }
483
484 //---------------------------------------------------------
485 // valueChanged
486 //---------------------------------------------------------
valueChanged()487 void EditDrumset::valueChanged()
488 {
489 if(!pitchList->currentItem())
490 return;
491 int pitch = pitchList->currentItem()->data(Column::PITCH, Qt::UserRole).toInt();
492 nDrumset.drum(pitch).name = name->text();
493 if (customGbox->isChecked() || noteHead->currentIndex() == noteHead->findData(int(NoteHead::Group::HEAD_CUSTOM))) {
494 fillCustomNoteheadsDataFromComboboxes(pitch);
495 setCustomNoteheadsGUIEnabled(true);
496 }
497 else {
498 nDrumset.drum(pitch).notehead = NoteHead::Group(noteHead->currentData().toInt());
499 fillNoteheadsComboboxes(false, pitch);
500 setCustomNoteheadsGUIEnabled(false);
501 }
502
503 nDrumset.drum(pitch).line = staffLine->value();
504 nDrumset.drum(pitch).voice = voice->currentIndex();
505 nDrumset.drum(pitch).stemDirection = Direction(stemDirection->currentIndex());
506 if (QString(QChar(nDrumset.drum(pitch).shortcut)) != shortcut->currentText()) {
507 if (shortcut->currentText().isEmpty())
508 nDrumset.drum(pitch).shortcut = 0;
509 else
510 nDrumset.drum(pitch).shortcut = shortcut->currentText().at(0).toLatin1();
511 }
512 updateExample();
513 }
514
515 //---------------------------------------------------------
516 // updateExample
517 //---------------------------------------------------------
updateExample()518 void EditDrumset::updateExample()
519 {
520 int pitch = pitchList->currentItem()->data(0, Qt::UserRole).toInt();
521 if (!nDrumset.isValid(pitch)) {
522 drumNote->add(0, 0, "");
523 return;
524 }
525 int line = nDrumset.line(pitch);
526 NoteHead::Group nh = nDrumset.noteHead(pitch);
527 int v = nDrumset.voice(pitch);
528 Direction dir = nDrumset.stemDirection(pitch);
529 bool up = (Direction::UP == dir) || (Direction::AUTO == dir && line > 4);
530 Chord* chord = new Chord(gscore);
531 chord->setDurationType(TDuration::DurationType::V_QUARTER);
532 chord->setStemDirection(dir);
533 chord->setTrack(v);
534 chord->setUp(up);
535 Note* note = new Note(gscore);
536 note->setParent(chord);
537 note->setTrack(v);
538 note->setPitch(pitch);
539 note->setTpcFromPitch();
540 note->setLine(line);
541 note->setPos(0.0, gscore->spatium() * .5 * line);
542 note->setHeadType(NoteHead::Type::HEAD_QUARTER);
543 note->setHeadGroup(nh);
544 note->setCachedNoteheadSym(Sym::name2id(quarterCmb->currentData().toString()));
545 chord->add(note);
546 Stem* stem = new Stem(gscore);
547 stem->setLen((up ? -3.0 : 3.0) * gscore->spatium());
548 chord->add(stem);
549 drumNote->add(0, chord, qApp->translate("drumset", nDrumset.name(pitch).toUtf8().constData()));
550 }
551
552 //---------------------------------------------------------
553 // load
554 //---------------------------------------------------------
555
load()556 void EditDrumset::load()
557 {
558 QString fname = mscore->getDrumsetFilename(true);
559 if (fname.isEmpty())
560 return;
561
562 QFile fp(fname);
563 if (!fp.open(QIODevice::ReadOnly))
564 return;
565
566 XmlReader e(&fp);
567 nDrumset.clear();
568 while (e.readNextStartElement()) {
569 if (e.name() == "museScore") {
570 if (e.attribute("version") != MSC_VERSION) {
571 QMessageBox::StandardButton b = QMessageBox::warning(this, tr("Drumset file too old"),
572 tr("MuseScore may not be able to load this drumset file."),
573 QMessageBox::Cancel|QMessageBox::Ignore, QMessageBox::Cancel);
574 if (b != QMessageBox::Ignore) // covers Cancel and Esc
575 return;
576 }
577 while (e.readNextStartElement()) {
578 if (e.name() == "Drum")
579 nDrumset.load(e);
580 else
581 e.unknown();
582 }
583 }
584 }
585 fp.close();
586 updatePitchesList();
587 }
588
589 //---------------------------------------------------------
590 // save
591 //---------------------------------------------------------
592
save()593 void EditDrumset::save()
594 {
595 QString fname = mscore->getDrumsetFilename(false);
596 if (fname.isEmpty())
597 return;
598
599 QFile f(fname);
600 if (!f.open(QIODevice::WriteOnly)) {
601 QString s = tr("Open File\n%1\nfailed: %2").arg(f.fileName()).arg(strerror(errno));
602 QMessageBox::critical(mscore, tr("Open File"), s);
603 return;
604 }
605 valueChanged(); //save last changes in name
606 XmlWriter xml(0, &f);
607 xml.header();
608 xml.stag("museScore version=\"" MSC_VERSION "\"");
609 nDrumset.save(xml);
610 xml.etag();
611 if (f.error() != QFile::NoError) {
612 QString s = tr("Write File failed: %1").arg(f.errorString());
613 QMessageBox::critical(this, tr("Write Drumset"), s);
614 }
615 }
616
617 //---------------------------------------------------------
618 // hideEvent
619 //---------------------------------------------------------
hideEvent(QHideEvent * event)620 void EditDrumset::hideEvent(QHideEvent* event)
621 {
622 MuseScore::saveGeometry(this);
623 QDialog::hideEvent(event);
624 }
625
626 //---------------------------------------------------------
627 // customQuarterChanged
628 //---------------------------------------------------------
customQuarterChanged(int)629 void EditDrumset::customQuarterChanged(int)
630 {
631 updateExample();
632 }
633 }
634