1 //=============================================================================
2 //  MuseScore
3 //  Linux Music Score Editor
4 //
5 //  Copyright (C) 2010-2016 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 "drumtools.h"
21 #include "musescore.h"
22 #include "palette.h"
23 #include "libmscore/chord.h"
24 #include "libmscore/note.h"
25 #include "libmscore/drumset.h"
26 #include "libmscore/score.h"
27 #include "preferences.h"
28 #include "seq.h"
29 #include "editdrumset.h"
30 #include "libmscore/staff.h"
31 #include "libmscore/part.h"
32 #include "libmscore/stem.h"
33 #include "libmscore/mscore.h"
34 #include "libmscore/undo.h"
35 
36 namespace Ms {
37 
38 //---------------------------------------------------------
39 //   DrumTools
40 //---------------------------------------------------------
41 
DrumTools(QWidget * parent)42 DrumTools::DrumTools(QWidget* parent)
43    : QDockWidget(parent)
44       {
45       drumset = 0;
46       _score  = 0;
47       setObjectName("drum-tools");
48       setAllowedAreas(Qt::DockWidgetAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea));
49 
50       QWidget* w = new QWidget(this);
51       w->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
52       w->setMaximumHeight(100 * Palette::guiMag());
53       QHBoxLayout* layout = new QHBoxLayout;
54       w->setLayout(layout);
55 
56       QVBoxLayout* layout1 = new QVBoxLayout;
57       layout1->setSpacing(6);
58       pitchName = new QLabel;
59       pitchName->setAlignment(Qt::AlignCenter);
60       pitchName->setWordWrap(true);
61       pitchName->setContentsMargins(25, 0, 25, 0);
62       layout1->addWidget(pitchName);
63 
64       QHBoxLayout* buttonLayout = new QHBoxLayout;
65       buttonLayout->setContentsMargins(5, 5, 5, 5);
66       editButton = new QToolButton;
67       editButton->setMinimumWidth(175);
68       editButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
69       buttonLayout->addWidget(editButton);
70       layout1->addLayout(buttonLayout);
71       layout->addLayout(layout1);
72 
73       drumPalette = new Palette;
74       drumPalette->setMag(0.8);
75       drumPalette->setSelectable(true);
76       drumPalette->setUseDoubleClickToActivate(true);
77       drumPalette->setGrid(28, 60);
78       PaletteScrollArea* sa = new PaletteScrollArea(drumPalette);
79       sa->setFocusPolicy(Qt::NoFocus);
80       layout->addWidget(sa);
81 
82       setWidget(w);
83 
84       w = new QWidget(this);
85       setTitleBarWidget(w);
86       titleBarWidget()->hide();
87       connect(editButton, SIGNAL(clicked()), SLOT(editDrumset()));
88       void boxClicked(int);
89       connect(drumPalette, SIGNAL(boxClicked(int)), SLOT(drumNoteSelected(int)));
90       retranslate();
91       drumPalette->setContextMenuPolicy(Qt::PreventContextMenu);
92       }
93 
94 //---------------------------------------------------------
95 //   updateDrumset
96 //---------------------------------------------------------
97 
retranslate()98 void DrumTools::retranslate()
99       {
100       setWindowTitle(tr("Drumset Tools"));
101       editButton->setText(tr("Edit Drumset"));
102       drumPalette->setName(tr("Drumset"));
103       }
104 
105 //---------------------------------------------------------
106 //   updateDrumset
107 //---------------------------------------------------------
108 
updateDrumset(const Drumset * ds)109 void DrumTools::updateDrumset(const Drumset* ds)
110       {
111       drumPalette->clear();
112       drumset = ds;
113       if (!drumset)
114             return;
115       double _spatium = gscore->spatium();
116       for (int pitch = 0; pitch < 128; ++pitch) {
117             if (!drumset->isValid(pitch))
118                   continue;
119             bool up;
120             int line      = drumset->line(pitch);
121             NoteHead::Group noteHead  = drumset->noteHead(pitch);
122             int voice     = drumset->voice(pitch);
123             Direction dir = drumset->stemDirection(pitch);
124             if (dir == Direction::UP)
125                   up = true;
126             else if (dir == Direction::DOWN)
127                   up = false;
128             else
129                   up = line > 4;
130 
131             Chord* chord = new Chord(gscore);
132             chord->setDurationType(TDuration::DurationType::V_QUARTER);
133             chord->setStemDirection(dir);
134             chord->setUp(up);
135             chord->setTrack(voice);
136             Stem* stem = new Stem(gscore);
137             stem->setLen((up ? -3.0 : 3.0) * _spatium);
138             chord->add(stem);
139             Note* note = new Note(gscore);
140             note->setMark(true);
141             note->setParent(chord);
142             note->setTrack(voice);
143             note->setPitch(pitch);
144             note->setTpcFromPitch();
145             note->setLine(line);
146             note->setPos(0.0, _spatium * .5 * line);
147             note->setHeadGroup(noteHead);
148             SymId noteheadSym = SymId::noteheadBlack;
149             if (noteHead == NoteHead::Group::HEAD_CUSTOM)
150                   noteheadSym = drumset->noteHeads(pitch, NoteHead::Type::HEAD_QUARTER);
151             else
152                   noteheadSym = note->noteHead(true, noteHead, NoteHead::Type::HEAD_QUARTER);
153 
154             note->setCachedNoteheadSym(noteheadSym); // we use the cached notehead so we don't recompute it at each layout
155             chord->add(note);
156             int sc = drumset->shortcut(pitch);
157             QString shortcut;
158             if (sc)
159                   shortcut = QChar(sc);
160             drumPalette->append(chord, qApp->translate("drumset", drumset->name(pitch).toUtf8().data()), shortcut);
161             }
162       }
163 
164 //---------------------------------------------------------
165 //   setDrumset
166 //---------------------------------------------------------
167 
setDrumset(Score * s,Staff * st,const Drumset * ds)168 void DrumTools::setDrumset(Score* s, Staff* st, const Drumset* ds)
169       {
170       if (s == _score && staff == st && drumset == ds)
171             return;
172       _score  = s;
173       staff   = st;
174       //drumset = ds;
175       updateDrumset(ds);
176       }
177 
178 //---------------------------------------------------------
179 //   editDrumset
180 //---------------------------------------------------------
181 
editDrumset()182 void DrumTools::editDrumset()
183       {
184       EditDrumset eds(drumset, this);
185       if (eds.exec()) {
186             ChordRest* cr = _score->getSelectedChordRest();
187             Fraction tick = cr ? cr->tick() : Fraction(0,1);
188             _score->startCmd();
189             _score->undo(new ChangeDrumset(staff->part()->instrument(tick), eds.drumset()));
190             mscore->updateDrumTools(eds.drumset());
191             if (_score->undoStack()->active()) {
192                   _score->setLayoutAll();
193                   _score->endCmd();
194                   }
195             }
196       }
197 
198 //---------------------------------------------------------
199 //   drumNoteSelected
200 //---------------------------------------------------------
201 
drumNoteSelected(int val)202 void DrumTools::drumNoteSelected(int val)
203       {
204       Element* element = drumPalette->element(val);
205       if (element && element->type() == ElementType::CHORD) {
206             Chord* ch        = static_cast<Chord*>(element);
207             Note* note       = ch->downNote();
208             int ticks        = MScore::defaultPlayDuration;
209             int pitch        = note->pitch();
210             seq->startNote(staff->part()->instrument()->channel(0)->channel(), pitch, 80, ticks, 0.0);  //tick?
211 
212             int track = (_score->inputState().track() / VOICES) * VOICES + element->track();
213             _score->inputState().setTrack(track);
214             _score->inputState().setDrumNote(pitch);
215 
216             getAction("voice-1")->setChecked(element->voice() == 0);
217             getAction("voice-2")->setChecked(element->voice() == 1);
218             getAction("voice-3")->setChecked(element->voice() == 2);
219             getAction("voice-4")->setChecked(element->voice() == 3);
220 
221             auto pitchCell = drumPalette->cellAt(val);
222             pitchName->setText(pitchCell->name);
223             }
224       }
225 
selectedDrumNote()226 int DrumTools::selectedDrumNote()
227       {
228       int idx = drumPalette->getSelectedIdx();
229       if (idx < 0)
230             return -1;
231       Element* element = drumPalette->element(idx);
232       if (element && element->type() == ElementType::CHORD) {
233             Chord* ch  = static_cast<Chord*>(element);
234             Note* note = ch->downNote();
235             auto pitchCell = drumPalette->cellAt(idx);
236             pitchName->setText(pitchCell->name);
237             return note->pitch();
238             }
239       else {
240             return -1;
241             }
242       }
243 
changeEvent(QEvent * event)244 void DrumTools::changeEvent(QEvent *event)
245       {
246       QDockWidget::changeEvent(event);
247       if (event->type() == QEvent::LanguageChange)
248             retranslate();
249       }
250 }
251 
252