1 /*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
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 as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 #include "PatternEditorInstrumentList.h"
24
25 #include <hydrogen/audio_engine.h>
26 #include <hydrogen/event_queue.h>
27 #include <hydrogen/hydrogen.h>
28 #include <hydrogen/basics/instrument.h>
29 #include <hydrogen/basics/instrument_list.h>
30 #include <hydrogen/basics/note.h>
31 #include <hydrogen/basics/pattern.h>
32 #include <hydrogen/basics/pattern_list.h>
33 #include <hydrogen/Preferences.h>
34 #include <hydrogen/basics/song.h>
35 #include <hydrogen/LocalFileMng.h>
36 using namespace H2Core;
37
38 #include "UndoActions.h"
39 #include "PatternEditorPanel.h"
40 #include "InstrumentEditor/InstrumentEditorPanel.h"
41 #include "DrumPatternEditor.h"
42 #include "../HydrogenApp.h"
43 #include "../Mixer/Mixer.h"
44 #include "../Widgets/Button.h"
45
46 #include <QtGui>
47 #if QT_VERSION >= 0x050000
48 # include <QtWidgets>
49 #endif
50 #include <QClipboard>
51 #include <cassert>
52 #include <algorithm> // for std::min
53
54 using namespace std;
55
56 const char* InstrumentLine::__class_name = "InstrumentLine";
57
InstrumentLine(QWidget * pParent)58 InstrumentLine::InstrumentLine(QWidget* pParent)
59 : PixmapWidget(pParent, __class_name)
60 , m_bIsSelected(false)
61 {
62 int h = Preferences::get_instance()->getPatternEditorGridHeight();
63 setFixedSize(181, h);
64
65 m_pNameLbl = new QLabel(this);
66 m_pNameLbl->resize( 145, h );
67 m_pNameLbl->move( 10, 1 );
68 QFont nameFont;
69 nameFont.setPointSize( 10 );
70 nameFont.setBold( true );
71 m_pNameLbl->setFont(nameFont);
72
73 m_pMuteBtn = new ToggleButton(
74 this,
75 "/mixerPanel/btn_mute_on.png",
76 "/mixerPanel/btn_mute_off.png",
77 "/mixerPanel/btn_mute_off.png",
78 QSize( 18, 13 )
79 );
80 m_pMuteBtn->move( 145, 5 );
81 m_pMuteBtn->setPressed(false);
82 m_pMuteBtn->setToolTip( tr("Mute instrument") );
83 connect(m_pMuteBtn, SIGNAL(clicked(Button*)), this, SLOT(muteClicked()));
84
85 m_pSoloBtn = new ToggleButton(
86 this,
87 "/mixerPanel/btn_solo_on.png",
88 "/mixerPanel/btn_solo_off.png",
89 "/mixerPanel/btn_solo_off.png",
90 QSize( 18, 13 )
91 );
92 m_pSoloBtn->move( 163, 5 );
93 m_pSoloBtn->setPressed(false);
94 m_pSoloBtn->setToolTip( tr("Solo") );
95 connect(m_pSoloBtn, SIGNAL(clicked(Button*)), this, SLOT(soloClicked()));
96
97
98
99 // Popup menu
100 m_pFunctionPopup = new QMenu( this );
101 m_pFunctionPopup->addAction( tr( "Clear notes" ), this, SLOT( functionClearNotes() ) );
102
103 m_pFunctionPopupSub = new QMenu( tr( "Fill notes ..." ), m_pFunctionPopup );
104 m_pFunctionPopupSub->addAction( tr( "Fill all notes" ), this, SLOT( functionFillAllNotes() ) );
105 m_pFunctionPopupSub->addAction( tr( "Fill 1/2 notes" ), this, SLOT( functionFillEveryTwoNotes() ) );
106 m_pFunctionPopupSub->addAction( tr( "Fill 1/3 notes" ), this, SLOT( functionFillEveryThreeNotes() ) );
107 m_pFunctionPopupSub->addAction( tr( "Fill 1/4 notes" ), this, SLOT( functionFillEveryFourNotes() ) );
108 m_pFunctionPopupSub->addAction( tr( "Fill 1/6 notes" ), this, SLOT( functionFillEverySixNotes() ) );
109 m_pFunctionPopupSub->addAction( tr( "Fill 1/8 notes" ), this, SLOT( functionFillEveryEightNotes() ) );
110 m_pFunctionPopupSub->addAction( tr( "Fill 1/12 notes" ), this, SLOT( functionFillEveryTwelveNotes() ) );
111 m_pFunctionPopupSub->addAction( tr( "Fill 1/16 notes" ), this, SLOT( functionFillEverySixteenNotes() ) );
112 m_pFunctionPopup->addMenu( m_pFunctionPopupSub );
113
114 m_pFunctionPopup->addAction( tr( "Randomize velocity" ), this, SLOT( functionRandomizeVelocity() ) );
115 m_pFunctionPopup->addSeparator();
116
117 m_pCopyPopupSub = new QMenu( tr( "Copy notes ..." ), m_pFunctionPopup );
118 m_pCopyPopupSub->addAction( tr( "Only for this pattern" ), this, SLOT( functionCopyInstrumentPattern() ) );
119 m_pCopyPopupSub->addAction( tr( "For all patterns" ), this, SLOT( functionCopyAllInstrumentPatterns() ) );
120 m_pFunctionPopup->addMenu( m_pCopyPopupSub );
121
122 m_pPastePopupSub = new QMenu( tr( "Paste notes ..." ), m_pFunctionPopup );
123 m_pPastePopupSub->addAction( tr( "Only for this pattern" ), this, SLOT( functionPasteInstrumentPattern() ) );
124 m_pPastePopupSub->addAction( tr( "For all patterns" ), this, SLOT( functionPasteAllInstrumentPatterns() ) );
125 m_pFunctionPopup->addMenu( m_pPastePopupSub );
126
127 m_pFunctionPopup->addSeparator();
128 m_pFunctionPopup->addAction( tr( "Rename instrument" ), this, SLOT( functionRenameInstrument() ) );
129 m_pFunctionPopup->addAction( tr( "Delete instrument" ), this, SLOT( functionDeleteInstrument() ) );
130
131 m_bIsSelected = true;
132 setSelected(false);
133 }
134
135
136
setName(const QString & sName)137 void InstrumentLine::setName(const QString& sName)
138 {
139 m_pNameLbl->setText(sName);
140 }
141
142
143
setSelected(bool bSelected)144 void InstrumentLine::setSelected(bool bSelected)
145 {
146 if (bSelected == m_bIsSelected) {
147 return;
148 }
149 m_bIsSelected = bSelected;
150 if (m_bIsSelected) {
151 setPixmap( "/patternEditor/instrument_line_selected.png");
152 }
153 else {
154 setPixmap( "/patternEditor/instrument_line.png");
155 }
156 }
157
158
159
setNumber(int nIndex)160 void InstrumentLine::setNumber(int nIndex)
161 {
162 m_nInstrumentNumber = nIndex;
163 }
164
165
166
setMuted(bool isMuted)167 void InstrumentLine::setMuted(bool isMuted)
168 {
169 m_pMuteBtn->setPressed(isMuted);
170 }
171
172
setSoloed(bool soloed)173 void InstrumentLine::setSoloed( bool soloed )
174 {
175 m_pSoloBtn->setPressed( soloed );
176 }
177
178
179
muteClicked()180 void InstrumentLine::muteClicked()
181 {
182 Hydrogen *pEngine = Hydrogen::get_instance();
183 Song *pSong = pEngine->getSong();
184 InstrumentList *pInstrList = pSong->get_instrument_list();
185 Instrument *pInstr = pInstrList->get( m_nInstrumentNumber );
186
187 CoreActionController* pCoreActionController = pEngine->getCoreActionController();
188 pCoreActionController->setStripIsMuted( m_nInstrumentNumber, !pInstr->is_muted() );
189 }
190
191
192
soloClicked()193 void InstrumentLine::soloClicked()
194 {
195 HydrogenApp::get_instance()->getMixer()->soloClicked( m_nInstrumentNumber );
196 }
197
198
199
mousePressEvent(QMouseEvent * ev)200 void InstrumentLine::mousePressEvent(QMouseEvent *ev)
201 {
202 Hydrogen::get_instance()->setSelectedInstrumentNumber( m_nInstrumentNumber );
203 HydrogenApp::get_instance()->getPatternEditorPanel()->updatePianorollEditor();
204
205 if ( ev->button() == Qt::LeftButton ) {
206 const int width = m_pMuteBtn->x() - 5; // clickable field width
207 const float velocity = std::min((float)ev->x()/(float)width, 1.0f);
208 const float pan_L = 0.5f;
209 const float pan_R = 0.5f;
210 const int nLength = -1;
211 const float fPitch = 0.0f;
212 Song *pSong = Hydrogen::get_instance()->getSong();
213
214 Instrument *pInstr = pSong->get_instrument_list()->get( m_nInstrumentNumber );
215
216 Note *pNote = new Note( pInstr, 0, velocity, pan_L, pan_R, nLength, fPitch);
217 AudioEngine::get_instance()->get_sampler()->note_on(pNote);
218 }
219 else if (ev->button() == Qt::RightButton ) {
220 m_pFunctionPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
221 }
222
223 // propago l'evento al parent: serve per il drag&drop
224 PixmapWidget::mousePressEvent(ev);
225 }
226
227
228
getCurrentPattern()229 H2Core::Pattern* InstrumentLine::getCurrentPattern()
230 {
231 Hydrogen *pEngine = Hydrogen::get_instance();
232 PatternList *pPatternList = pEngine->getSong()->get_pattern_list();
233 assert( pPatternList != nullptr );
234
235 int nSelectedPatternNumber = pEngine->getSelectedPatternNumber();
236 if ( nSelectedPatternNumber != -1 ) {
237 Pattern* pCurrentPattern = pPatternList->get( nSelectedPatternNumber );
238 return pCurrentPattern;
239 }
240 return nullptr;
241 }
242
243
244
245
functionClearNotes()246 void InstrumentLine::functionClearNotes()
247 {
248 Hydrogen * pEngine = Hydrogen::get_instance();
249 int selectedPatternNr = pEngine->getSelectedPatternNumber();
250 Pattern *pPattern = getCurrentPattern();
251 Instrument *pSelectedInstrument = pEngine->getSong()->get_instrument_list()->get( m_nInstrumentNumber );
252
253 std::list< Note* > noteList;
254 const Pattern::notes_t* notes = pPattern->get_notes();
255 FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
256 Note *pNote = it->second;
257 assert( pNote );
258 if ( pNote->get_instrument() == pSelectedInstrument ) {
259 noteList.push_back( pNote );
260 }
261 }
262 if( noteList.size() > 0 ){
263 SE_clearNotesPatternEditorAction *action = new SE_clearNotesPatternEditorAction( noteList, m_nInstrumentNumber,selectedPatternNr);
264 HydrogenApp::get_instance()->m_pUndoStack->push( action );
265 }
266 }
267
functionCopyInstrumentPattern()268 void InstrumentLine::functionCopyInstrumentPattern()
269 {
270 Hydrogen * pEngine = Hydrogen::get_instance();
271 int selectedPatternNr = pEngine->getSelectedPatternNumber();
272 Song *song = pEngine->getSong();
273 assert(song);
274
275 // Serialize & put to clipboard
276 QString serialized = song->copyInstrumentLineToString( selectedPatternNr, m_nInstrumentNumber );
277 QClipboard *clipboard = QApplication::clipboard();
278 clipboard->setText(serialized);
279 }
280
functionCopyAllInstrumentPatterns()281 void InstrumentLine::functionCopyAllInstrumentPatterns()
282 {
283 Hydrogen * pEngine = Hydrogen::get_instance();
284 Song *song = pEngine->getSong();
285 assert(song);
286
287 // Serialize & put to clipboard
288 QString serialized = song->copyInstrumentLineToString( -1, m_nInstrumentNumber );
289 QClipboard *clipboard = QApplication::clipboard();
290 clipboard->setText(serialized);
291 }
292
functionPasteInstrumentPattern()293 void InstrumentLine::functionPasteInstrumentPattern()
294 {
295 Hydrogen * pEngine = Hydrogen::get_instance();
296 int selectedPatternNr = pEngine->getSelectedPatternNumber();
297
298 functionPasteInstrumentPatternExec(selectedPatternNr);
299 }
300
functionPasteAllInstrumentPatterns()301 void InstrumentLine::functionPasteAllInstrumentPatterns()
302 {
303 functionPasteInstrumentPatternExec(-1);
304 }
305
functionPasteInstrumentPatternExec(int patternID)306 void InstrumentLine::functionPasteInstrumentPatternExec(int patternID)
307 {
308 Hydrogen * pEngine = Hydrogen::get_instance();
309 Song *song = pEngine->getSong();
310 assert(song);
311
312 // This is a note list for pasted notes collection
313 std::list< Pattern* > patternList;
314
315 // Get from clipboard & deserialize
316 QClipboard *clipboard = QApplication::clipboard();
317 QString serialized = clipboard->text();
318 if ( !song->pasteInstrumentLineFromString( serialized, patternID, m_nInstrumentNumber, patternList ) )
319 return;
320
321 // Ignore empty result
322 if (patternList.size() <= 0)
323 return;
324
325 // Create action
326 SE_pasteNotesPatternEditorAction *action = new SE_pasteNotesPatternEditorAction(patternList);
327 HydrogenApp::get_instance()->m_pUndoStack->push(action);
328 }
329
330
functionFillAllNotes()331 void InstrumentLine::functionFillAllNotes(){ functionFillNotes(1); }
functionFillEveryTwoNotes()332 void InstrumentLine::functionFillEveryTwoNotes(){ functionFillNotes(2); }
functionFillEveryThreeNotes()333 void InstrumentLine::functionFillEveryThreeNotes(){ functionFillNotes(3); }
functionFillEveryFourNotes()334 void InstrumentLine::functionFillEveryFourNotes(){ functionFillNotes(4); }
functionFillEverySixNotes()335 void InstrumentLine::functionFillEverySixNotes(){ functionFillNotes(6); }
functionFillEveryEightNotes()336 void InstrumentLine::functionFillEveryEightNotes(){ functionFillNotes(8); }
functionFillEveryTwelveNotes()337 void InstrumentLine::functionFillEveryTwelveNotes(){ functionFillNotes(12); }
functionFillEverySixteenNotes()338 void InstrumentLine::functionFillEverySixteenNotes(){ functionFillNotes(16); }
339
functionFillNotes(int every)340 void InstrumentLine::functionFillNotes( int every )
341 {
342 Hydrogen *pEngine = Hydrogen::get_instance();
343
344 PatternEditorPanel *pPatternEditorPanel = HydrogenApp::get_instance()->getPatternEditorPanel();
345 DrumPatternEditor *pPatternEditor = pPatternEditorPanel->getDrumPatternEditor();
346 int nBase;
347 if ( pPatternEditor->isUsingTriplets() ) {
348 nBase = 3;
349 }
350 else {
351 nBase = 4;
352 }
353 int nResolution = 4 * MAX_NOTES * every / ( nBase * pPatternEditor->getResolution() );
354
355
356 Song *pSong = pEngine->getSong();
357
358 QStringList notePositions;
359
360 Pattern* pCurrentPattern = getCurrentPattern();
361 if (pCurrentPattern != nullptr) {
362 int nPatternSize = pCurrentPattern->get_length();
363 int nSelectedInstrument = pEngine->getSelectedInstrumentNumber();
364
365 if (nSelectedInstrument != -1) {
366 Instrument *instrRef = (pSong->get_instrument_list())->get( nSelectedInstrument );
367
368 for (int i = 0; i < nPatternSize; i += nResolution) {
369 bool noteAlreadyPresent = false;
370 const Pattern::notes_t* notes = pCurrentPattern->get_notes();
371 FOREACH_NOTE_CST_IT_BOUND(notes,it,i) {
372 Note *pNote = it->second;
373 if ( pNote->get_instrument() == instrRef ) {
374 // note already exists
375 noteAlreadyPresent = true;
376 break;
377 }
378 }
379
380 if ( noteAlreadyPresent == false ) {
381 notePositions << QString("%1").arg(i);
382 }
383 }
384 SE_fillNotesRightClickAction *action = new SE_fillNotesRightClickAction( notePositions, nSelectedInstrument, pEngine->getSelectedPatternNumber() );
385 HydrogenApp::get_instance()->m_pUndoStack->push( action );
386 }
387 }
388
389 }
390
391
392
functionRandomizeVelocity()393 void InstrumentLine::functionRandomizeVelocity()
394 {
395 Hydrogen *pEngine = Hydrogen::get_instance();
396
397 PatternEditorPanel *pPatternEditorPanel = HydrogenApp::get_instance()->getPatternEditorPanel();
398 DrumPatternEditor *pPatternEditor = pPatternEditorPanel->getDrumPatternEditor();
399
400
401 int nBase;
402 if ( pPatternEditor->isUsingTriplets() ) {
403 nBase = 3;
404 }
405 else {
406 nBase = 4;
407 }
408 int nResolution = 4 * MAX_NOTES / ( nBase * pPatternEditor->getResolution() );
409
410 Song *pSong = pEngine->getSong();
411
412 QStringList noteVeloValue;
413 QStringList oldNoteVeloValue;
414
415 Pattern* pCurrentPattern = getCurrentPattern();
416 if (pCurrentPattern != nullptr) {
417 int nPatternSize = pCurrentPattern->get_length();
418 int nSelectedInstrument = pEngine->getSelectedInstrumentNumber();
419
420 if (nSelectedInstrument != -1) {
421 Instrument *instrRef = (pSong->get_instrument_list())->get( nSelectedInstrument );
422
423 for (int i = 0; i < nPatternSize; i += nResolution) {
424 const Pattern::notes_t* notes = pCurrentPattern->get_notes();
425 FOREACH_NOTE_CST_IT_BOUND(notes,it,i) {
426 Note *pNote = it->second;
427 if ( pNote->get_instrument() == instrRef ) {
428 float fVal = ( rand() % 100 ) / 100.0;
429 oldNoteVeloValue << QString("%1").arg( pNote->get_velocity() );
430 fVal = pNote->get_velocity() + ( ( fVal - 0.50 ) / 2 );
431 if ( fVal < 0 ) {
432 fVal = 0;
433 }
434 if ( fVal > 1 ) {
435 fVal = 1;
436 }
437 noteVeloValue << QString("%1").arg(fVal);
438 }
439 }
440 }
441 SE_randomVelocityRightClickAction *action = new SE_randomVelocityRightClickAction( noteVeloValue, oldNoteVeloValue, nSelectedInstrument, pEngine->getSelectedPatternNumber() );
442 HydrogenApp::get_instance()->m_pUndoStack->push( action );
443 }
444 }
445 }
446
447
448
functionRenameInstrument()449 void InstrumentLine::functionRenameInstrument()
450 {
451 // This code is pretty much a duplicate of void InstrumentEditor::labelClicked
452 // in InstrumentEditor.cpp
453 Hydrogen * pEngine = Hydrogen::get_instance();
454 Instrument *pSelectedInstrument = pEngine->getSong()->get_instrument_list()->get( m_nInstrumentNumber );
455
456 QString sOldName = pSelectedInstrument->get_name();
457 bool bIsOkPressed;
458 QString sNewName = QInputDialog::getText( this, "Hydrogen", tr( "New instrument name" ), QLineEdit::Normal, sOldName, &bIsOkPressed );
459 if ( bIsOkPressed ) {
460 pSelectedInstrument->set_name( sNewName );
461
462 #ifdef H2CORE_HAVE_JACK
463 AudioEngine::get_instance()->lock( RIGHT_HERE );
464 Hydrogen *engine = Hydrogen::get_instance();
465 engine->renameJackPorts(engine->getSong());
466 AudioEngine::get_instance()->unlock();
467 #endif
468
469 // this will force an update...
470 EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 );
471
472 }
473 else
474 {
475 // user entered nothing or pressed Cancel
476 }
477
478 }
479
functionDeleteInstrument()480 void InstrumentLine::functionDeleteInstrument()
481 {
482 Hydrogen * pEngine = Hydrogen::get_instance();
483 Instrument *pSelectedInstrument = pEngine->getSong()->get_instrument_list()->get( m_nInstrumentNumber );
484
485 std::list< Note* > noteList;
486 Song* song = pEngine->getSong();
487 PatternList *patList = song->get_pattern_list();
488
489 QString instrumentName = pSelectedInstrument->get_name();
490 QString drumkitName = pEngine->getCurrentDrumkitname();
491
492 for ( int i = 0; i < patList->size(); i++ ) {
493 H2Core::Pattern *pPattern = song->get_pattern_list()->get(i);
494 const Pattern::notes_t* notes = pPattern->get_notes();
495 FOREACH_NOTE_CST_IT_BEGIN_END(notes,it) {
496 Note *pNote = it->second;
497 assert( pNote );
498 if ( pNote->get_instrument() == pSelectedInstrument ) {
499 pNote->set_pattern_idx( i );
500 noteList.push_back( pNote );
501 }
502 }
503 }
504 SE_deleteInstrumentAction *action = new SE_deleteInstrumentAction( noteList, drumkitName, instrumentName, m_nInstrumentNumber );
505 HydrogenApp::get_instance()->m_pUndoStack->push( action );
506 }
507
508
509
510 //////
511
512 const char* PatternEditorInstrumentList::__class_name = "PatternEditorInstrumentList";
513
PatternEditorInstrumentList(QWidget * parent,PatternEditorPanel * pPatternEditorPanel)514 PatternEditorInstrumentList::PatternEditorInstrumentList( QWidget *parent, PatternEditorPanel *pPatternEditorPanel )
515 : QWidget( parent )
516 , Object( __class_name )
517 {
518 //INFOLOG("INIT");
519 m_pPattern = nullptr;
520 m_pPatternEditorPanel = pPatternEditorPanel;
521
522 m_nGridHeight = Preferences::get_instance()->getPatternEditorGridHeight();
523
524 m_nEditorWidth = 181;
525 m_nEditorHeight = m_nGridHeight * MAX_INSTRUMENTS;
526
527 resize( m_nEditorWidth, m_nEditorHeight );
528
529
530 setAcceptDrops(true);
531
532 for ( int i = 0; i < MAX_INSTRUMENTS; ++i) {
533 m_pInstrumentLine[i] = nullptr;
534 }
535
536
537 updateInstrumentLines();
538
539 m_pUpdateTimer = new QTimer( this );
540 connect( m_pUpdateTimer, SIGNAL( timeout() ), this, SLOT( updateInstrumentLines() ) );
541 m_pUpdateTimer->start(50);
542
543 }
544
545
546
~PatternEditorInstrumentList()547 PatternEditorInstrumentList::~PatternEditorInstrumentList()
548 {
549 //INFOLOG( "DESTROY" );
550 m_pUpdateTimer->stop();
551 }
552
553
554
555
556 ///
557 /// Create a new InstrumentLine
558 ///
createInstrumentLine()559 InstrumentLine* PatternEditorInstrumentList::createInstrumentLine()
560 {
561 InstrumentLine *pLine = new InstrumentLine(this);
562 return pLine;
563 }
564
565
566
567 ///
568 /// Update every InstrumentLine, create or destroy lines if necessary.
569 ///
updateInstrumentLines()570 void PatternEditorInstrumentList::updateInstrumentLines()
571 {
572 //INFOLOG( "Update lines" );
573
574 Hydrogen *pEngine = Hydrogen::get_instance();
575 Song *pSong = pEngine->getSong();
576 InstrumentList *pInstrList = pSong->get_instrument_list();
577 Mixer * mixer = HydrogenApp::get_instance()->getMixer();
578
579 unsigned nSelectedInstr = pEngine->getSelectedInstrumentNumber();
580
581 unsigned nInstruments = pInstrList->size();
582 for ( unsigned nInstr = 0; nInstr < MAX_INSTRUMENTS; ++nInstr ) {
583 if ( nInstr >= nInstruments ) { // unused instrument! let's hide and destroy the mixerline!
584 if ( m_pInstrumentLine[ nInstr ] ) {
585 delete m_pInstrumentLine[ nInstr ];
586 m_pInstrumentLine[ nInstr ] = nullptr;
587
588 int newHeight = m_nGridHeight * nInstruments;
589 resize( width(), newHeight );
590
591 }
592 continue;
593 }
594 else {
595 if ( m_pInstrumentLine[ nInstr ] == nullptr ) {
596 // the instrument line doesn't exists..I'll create a new one!
597 m_pInstrumentLine[ nInstr ] = createInstrumentLine();
598 m_pInstrumentLine[nInstr]->move( 0, m_nGridHeight * nInstr );
599 m_pInstrumentLine[nInstr]->show();
600
601 int newHeight = m_nGridHeight * nInstruments;
602 resize( width(), newHeight );
603 }
604 InstrumentLine *pLine = m_pInstrumentLine[ nInstr ];
605 Instrument* pInstr = pInstrList->get(nInstr);
606 assert(pInstr);
607
608 pLine->setNumber(nInstr);
609 pLine->setName( pInstr->get_name() );
610 pLine->setSelected( nInstr == nSelectedInstr );
611 pLine->setMuted( pInstr->is_muted() );
612 if ( mixer ) {
613 pLine->setSoloed( mixer->isSoloClicked( nInstr ) );
614 }
615
616 }
617 }
618
619 }
620
621
622
623
dragEnterEvent(QDragEnterEvent * event)624 void PatternEditorInstrumentList::dragEnterEvent(QDragEnterEvent *event)
625 {
626 INFOLOG( "[dragEnterEvent]" );
627 if ( event->mimeData()->hasFormat("text/plain") ) {
628 Song *song = (Hydrogen::get_instance())->getSong();
629 int nInstruments = song->get_instrument_list()->size();
630 if ( nInstruments < MAX_INSTRUMENTS ) {
631 event->acceptProposedAction();
632 }
633 }
634 }
635
636
dropEvent(QDropEvent * event)637 void PatternEditorInstrumentList::dropEvent(QDropEvent *event)
638 {
639 //WARNINGLOG("Drop!");
640 QString sText = event->mimeData()->text();
641
642
643 if(sText.startsWith("Songs:") || sText.startsWith("Patterns:") || sText.startsWith("move pattern:") || sText.startsWith("drag pattern:")) return;
644
645 if (sText.startsWith("move instrument:")) {
646
647 Hydrogen *engine = Hydrogen::get_instance();
648 int nSourceInstrument = engine->getSelectedInstrumentNumber();
649
650 // Starting point for instument list is 50 lower than
651 // on the drum pattern editor
652
653 int pos_y = ( event->pos().x() >= m_nEditorWidth ) ? event->pos().y() - 50 : event->pos().y();
654
655 int nTargetInstrument = pos_y / m_nGridHeight;
656
657 if( nTargetInstrument >= engine->getSong()->get_instrument_list()->size() ){
658 nTargetInstrument = engine->getSong()->get_instrument_list()->size() - 1;
659 }
660
661 if ( nSourceInstrument == nTargetInstrument ) {
662 event->acceptProposedAction();
663 return;
664 }
665
666 SE_moveInstrumentAction *action = new SE_moveInstrumentAction( nSourceInstrument, nTargetInstrument );
667 HydrogenApp::get_instance()->m_pUndoStack->push( action );
668
669 event->acceptProposedAction();
670 }
671 if( sText.startsWith("importInstrument:") ) {
672 //an instrument was dragged from the soundlibrary browser to the patterneditor
673
674 sText = sText.remove(0,QString("importInstrument:").length());
675
676 QStringList tokens = sText.split( "::" );
677 QString sDrumkitName = tokens.at( 0 );
678 QString sInstrumentName = tokens.at( 1 );
679
680 int nTargetInstrument = event->pos().y() / m_nGridHeight;
681
682 /*
683 "X > 181": border between the instrument names on the left and the grid
684 Because the right part of the grid starts above the name column, we have to subtract the difference
685 */
686 if ( event->pos().x() > 181 ) nTargetInstrument = ( event->pos().y() - 90 ) / m_nGridHeight ;
687
688 Hydrogen *engine = Hydrogen::get_instance();
689 if( nTargetInstrument > engine->getSong()->get_instrument_list()->size() ){
690 nTargetInstrument = engine->getSong()->get_instrument_list()->size();
691 }
692
693 SE_dragInstrumentAction *action = new SE_dragInstrumentAction( sDrumkitName, sInstrumentName, nTargetInstrument);
694 HydrogenApp::get_instance()->m_pUndoStack->push( action );
695
696 event->acceptProposedAction();
697 }
698 }
699
700
701
mousePressEvent(QMouseEvent * event)702 void PatternEditorInstrumentList::mousePressEvent(QMouseEvent *event)
703 {
704 if (event->button() == Qt::LeftButton) {
705 __drag_start_position = event->pos();
706 }
707
708 }
709
710
711
mouseMoveEvent(QMouseEvent * event)712 void PatternEditorInstrumentList::mouseMoveEvent(QMouseEvent *event)
713 {
714 if (!(event->buttons() & Qt::LeftButton)) {
715 return;
716 }
717 if ( abs(event->pos().y() - __drag_start_position.y()) < (int)m_nGridHeight) {
718 return;
719 }
720
721 Hydrogen *pEngine = Hydrogen::get_instance();
722 int nSelectedInstr = pEngine->getSelectedInstrumentNumber();
723 Instrument *pInstr = pEngine->getSong()->get_instrument_list()->get(nSelectedInstr);
724
725 QString sText = QString("move instrument:%1").arg( pInstr->get_name() );
726
727 QDrag *pDrag = new QDrag(this);
728 QMimeData *pMimeData = new QMimeData;
729
730 pMimeData->setText( sText );
731 pDrag->setMimeData( pMimeData);
732
733 pDrag->exec( Qt::CopyAction | Qt::MoveAction );
734
735 // propago l'evento
736 QWidget::mouseMoveEvent(event);
737 }
738