root/trunk/src/gui/src/SongEditor/SongEditor.cpp @ 2260

Revision 2260, 60.2 KB (checked in by jeremyz, 23 months ago)

use new PatternList? interface

Line 
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 <assert.h>
24#include <algorithm>
25#include <memory>
26
27#include <hydrogen/basics/song.h>
28#include <hydrogen/hydrogen.h>
29#include <hydrogen/Preferences.h>
30#include <hydrogen/basics/pattern.h>
31#include <hydrogen/basics/pattern_list.h>
32#include <hydrogen/audio_engine.h>
33#include <hydrogen/event_queue.h>
34#include <hydrogen/basics/instrument.h>
35using namespace H2Core;
36
37#include "UndoActions.h"
38#include "SongEditor.h"
39#include "SongEditorPanel.h"
40#include "SongEditorPanelBpmWidget.h"
41#include "SongEditorPanelTagWidget.h"
42#include "SoundLibrary/SoundLibraryPanel.h"
43#include "../PatternEditor/PatternEditorPanel.h"
44#include "../HydrogenApp.h"
45#include "../InstrumentRack.h"
46#include "../widgets/Button.h"
47#include "../PatternFillDialog.h"
48#include "../PatternPropertiesDialog.h"
49#include "../SongPropertiesDialog.h"
50#include "../Skin.h"
51#include "../VirtualPatternDialog.h"
52#include <hydrogen/LocalFileMng.h>
53
54
55using namespace std;
56
57const char* SongEditor::__class_name = "SongEditor";
58
59SongEditor::SongEditor( QWidget *parent )
60 : QWidget( parent )
61 , Object( __class_name )
62 , m_bSequenceChanged( true )
63 , m_bIsMoving( false )
64 , m_bShowLasso( false )
65{
66        setAttribute(Qt::WA_NoBackground);
67        setFocusPolicy (Qt::StrongFocus);
68
69        m_nGridWidth = 16;
70        m_nGridHeight = 18;
71
72        Preferences *pref = Preferences::get_instance();
73        m_nMaxPatternSequence = pref->getMaxBars();
74
75
76        int m_nInitialWidth = 10 + m_nMaxPatternSequence * m_nGridWidth;
77        int m_nInitialHeight = 10;
78
79        this->resize( QSize(m_nInitialWidth, m_nInitialHeight) );
80
81        createBackground();     // create m_backgroundPixmap pixmap
82
83        update();
84}
85
86
87
88SongEditor::~SongEditor()
89{
90}
91
92
93
94int SongEditor::getGridWidth ()
95{
96        return m_nGridWidth;
97}
98
99
100
101void SongEditor::setGridWidth( uint width )
102{
103        if ( ( SONG_EDITOR_MIN_GRID_WIDTH <= width ) && ( SONG_EDITOR_MAX_GRID_WIDTH >= width ) ) {
104                m_nGridWidth = width;
105                this->resize ( 10 + m_nMaxPatternSequence * m_nGridWidth, height() );
106        }
107}
108
109
110
111void SongEditor::keyPressEvent ( QKeyEvent * ev )
112{
113        Hydrogen *pEngine = Hydrogen::get_instance();
114        PatternList *pPatternList = pEngine->getSong()->get_pattern_list();
115        vector<PatternList*>* pColumns = pEngine->getSong()->get_pattern_group_vector();
116
117        if ( ev->key() == Qt::Key_Delete ) {
118                if ( m_selectedCells.size() != 0 ) {
119                        AudioEngine::get_instance()->lock( RIGHT_HERE );
120                        // delete all selected cells
121                        for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
122                                QPoint cell = m_selectedCells[ i ];
123                                PatternList* pColumn = (*pColumns)[ cell.x() ];
124                                pColumn->del(pPatternList->get( cell.y() ) );
125                        }
126                        AudioEngine::get_instance()->unlock();
127
128                        m_selectedCells.clear();
129                        m_bSequenceChanged = true;
130                        update();
131                }
132                return;
133        }
134
135        ev->ignore();
136}
137
138
139
140void SongEditor::mousePressEvent( QMouseEvent *ev )
141{
142        if ( ev->x() < 10 ) {
143                return;
144        }
145        //WARNINGLOG( "editor-pressed" );
146
147        int nRow = ev->y() / m_nGridHeight;
148        int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth;
149
150        if ( ev->modifiers() == Qt::ControlModifier ) {
151                INFOLOG( "[mousePressEvent] CTRL pressed!" );
152                m_bIsCtrlPressed = true;
153        }
154        else {
155                m_bIsCtrlPressed = false;
156        }
157
158        HydrogenApp* h2app = HydrogenApp::get_instance();
159        Hydrogen *pEngine = Hydrogen::get_instance();
160        Song *pSong = pEngine->getSong();
161        PatternList *pPatternList = pSong->get_pattern_list();
162
163        // don't lock the audio driver before checking that...
164        if ( nRow >= (int)pPatternList->size() || nRow < 0 || nColumn < 0 ) { return; }
165
166
167        SongEditorActionMode actionMode = HydrogenApp::get_instance()->getSongEditorPanel()->getActionMode();
168        if ( actionMode == SELECT_ACTION ) {
169                AudioEngine::get_instance()->lock( RIGHT_HERE );
170                bool bOverExistingPattern = false;
171                for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
172                        QPoint cell = m_selectedCells[ i ];
173                        if ( cell.x() == nColumn && cell.y() == nRow ) {
174                                bOverExistingPattern = true;
175                                break;
176                        }
177                }
178
179                if ( bOverExistingPattern ) {
180                        qDebug() << "select over existing!!";
181                        // MOVE PATTERNS
182//                      INFOLOG( "[mousePressEvent] Move patterns" );
183                        m_bIsMoving = true;
184                        m_bShowLasso = false;
185                        m_movingCells = m_selectedCells;
186
187                        m_clickPoint.setX( nColumn );
188                        m_clickPoint.setY( nRow );
189                }
190                else {
191//                      INFOLOG( "[mousePressEvent] Select patterns" );
192                        qDebug() << "select!!";
193                        // select patterns
194                        m_bShowLasso = true;
195                        m_lasso.setCoords( ev->x(), ev->y(), ev->x(), ev->y() );
196                        setCursor( QCursor( Qt::CrossCursor ) );
197                        m_selectedCells.clear();
198                        m_selectedCells.push_back( QPoint( nColumn, nRow ) );
199                }
200                AudioEngine::get_instance()->unlock();
201                // update
202                m_bSequenceChanged = true;
203                update();
204        }
205        else if ( actionMode == DRAW_ACTION ) {
206                H2Core::Pattern *pPattern = pPatternList->get( nRow );
207                vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();     // E' la lista di "colonne" di pattern
208                if ( nColumn < (int)pColumns->size() ) {
209                        PatternList *pColumn = ( *pColumns )[ nColumn ];
210
211                        bool bFound = false;
212                        unsigned nColumnIndex = 0;
213                        for ( nColumnIndex = 0; nColumnIndex < pColumn->size(); nColumnIndex++) {
214                                if ( pColumn->get( nColumnIndex ) == pPattern ) { // il pattern e' gia presente
215                                        bFound = true;
216                                        break;
217                                }
218                        }
219
220                        if ( bFound ) {//Delete pattern
221                                SE_deletePatternAction *action = new SE_deletePatternAction( nColumn, nRow, nColumnIndex) ;
222                                h2app->m_undoStack->push( action );
223
224                        }
225                        else {
226                                if ( nColumn < (int)pColumns->size() ) {
227                                    SE_addPatternAction *action = new SE_addPatternAction( nColumn, nRow, nColumnIndex ) ;
228                                    h2app->m_undoStack->push( action );
229                                }
230                        }
231                }
232                else {
233                        SE_addPatternAction *action = new SE_addPatternAction( nColumn, nRow, 0 ) ;
234                        h2app->m_undoStack->push( action );
235                }
236        }
237
238}
239
240
241void SongEditor::addPattern( int nColumn , int nRow )
242{
243        qDebug() << "add pattern!";
244        Hydrogen *pEngine = Hydrogen::get_instance();
245        Song *pSong = pEngine->getSong();
246        PatternList *pPatternList = pSong->get_pattern_list();
247        H2Core::Pattern *pPattern = pPatternList->get( nRow );
248        vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();
249
250        AudioEngine::get_instance()->lock( RIGHT_HERE );
251        if ( nColumn < (int)pColumns->size() ) {
252                PatternList *pColumn = ( *pColumns )[ nColumn ];
253                // ADD PATTERN
254                m_selectedCells.clear();
255                pColumn->add( pPattern );
256
257        } else {
258            //we need to add some new columns..
259            PatternList *pColumn = new PatternList();
260            m_selectedCells.clear();
261            int nSpaces = nColumn - pColumns->size();
262
263            pColumns->push_back( pColumn );
264
265            for ( int i = 0; i < nSpaces; i++ ) {
266                    pColumn = new PatternList();
267                    pColumns->push_back( pColumn );
268            }
269            pColumn->add( pPattern );
270        }
271        pSong->__is_modified = true;
272        AudioEngine::get_instance()->unlock();
273        m_bSequenceChanged = true;
274        update();
275}
276
277
278void SongEditor::deletePattern( int nColumn , int nRow, unsigned nColumnIndex )
279{
280        qDebug() << "delete pattern!";
281        Hydrogen *pEngine = Hydrogen::get_instance();
282        Song *pSong = pEngine->getSong();
283        PatternList *pPatternList = pSong->get_pattern_list();
284        H2Core::Pattern *pPattern = pPatternList->get( nRow );
285        vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();
286
287        AudioEngine::get_instance()->lock( RIGHT_HERE );
288
289        PatternList *pColumn = ( *pColumns )[ nColumn ];
290        pColumn->del( nColumnIndex );
291
292        // elimino le colonne vuote
293        for ( int i = pColumns->size() - 1; i >= 0; i-- ) {
294                PatternList *pColumn = ( *pColumns )[ i ];
295                if ( pColumn->size() == 0 ) {
296                        pColumns->erase( pColumns->begin() + i );
297                        delete pColumn;
298                }
299                else {
300                        break;
301                }
302        }
303        pSong->__is_modified = true;
304        AudioEngine::get_instance()->unlock();
305        m_bSequenceChanged = true;
306        update();
307}
308
309
310void SongEditor::mouseMoveEvent(QMouseEvent *ev)
311{
312        int nRow = ev->y() / m_nGridHeight;
313        int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth;
314        PatternList *pPatternList = Hydrogen::get_instance()->getSong()->get_pattern_list();
315        vector<PatternList*>* pColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector();
316
317        if ( m_bIsMoving ) {
318//              WARNINGLOG( "[mouseMoveEvent] Move patterns not implemented yet" );
319
320                int nRowDiff = nRow  - m_clickPoint.y();
321                int nColumnDiff = nColumn - m_clickPoint.x();
322//              INFOLOG( "[mouseMoveEvent] row diff: "+ to_string( nRowDiff ) );
323//              INFOLOG( "[mouseMoveEvent] col diff: "+ to_string( nColumnDiff ) );
324
325                for ( int i = 0; i < (int)m_movingCells.size(); i++ ) {
326                        QPoint cell = m_movingCells[ i ];
327                        m_movingCells[ i ].setX( m_selectedCells[ i ].x() + nColumnDiff );
328                        m_movingCells[ i ].setY( m_selectedCells[ i ].y() + nRowDiff );
329                }
330
331                m_bSequenceChanged = true;
332                update();
333                return;
334        }
335
336        if ( m_bShowLasso ) {
337                // SELECTION
338                setCursor( QCursor( Qt::CrossCursor ) );
339                int x = ev->x();
340                int y = ev->y();
341                if ( x < 0 ) {
342                        x = 0;
343                }
344                if ( y < 0 ) {
345                        y = 0;
346                }
347                m_lasso.setBottomRight( QPoint( x, y ) );
348
349                // aggiorno la lista di celle selezionate
350                m_selectedCells.clear();
351
352                int nStartColumn = (int)( ( m_lasso.left() - 10.0 ) / m_nGridWidth );
353                int nEndColumn = nColumn;
354                if ( nStartColumn > nEndColumn ) {
355                        int nTemp = nEndColumn;
356                        nEndColumn = nStartColumn;
357                        nStartColumn = nTemp;
358                }
359
360                int nStartRow = m_lasso.top() / m_nGridHeight;
361                int nEndRow = nRow;
362                if ( nStartRow > nEndRow ) {
363                        int nTemp = nEndRow;
364                        nEndRow = nStartRow;
365                        nStartRow = nTemp;
366                }
367
368                for ( int nRow = nStartRow; nRow <= nEndRow; nRow++ ) {
369                        for ( int nCol = nStartColumn; nCol <= nEndColumn; nCol++ ) {
370                                if ( nRow >= (int)pPatternList->size() || nRow < 0 || nCol < 0 ) {
371                                        return;
372                                }
373                                H2Core::Pattern *pPattern = pPatternList->get( nRow );
374
375                                if ( nCol < (int)pColumns->size() ) {
376                                        PatternList *pColumn = ( *pColumns )[ nCol ];
377
378                                        for ( uint i = 0; i < pColumn->size(); i++) {
379                                                if ( pColumn->get(i) == pPattern ) { // esiste un pattern in questa posizione
380                                                        m_selectedCells.push_back( QPoint( nCol, nRow ) );
381                                                }
382                                        }
383                                }
384                        }
385                }
386
387                m_bSequenceChanged = true;
388                update();
389        }
390
391}
392
393
394
395void SongEditor::mouseReleaseEvent( QMouseEvent *ev )
396{
397        UNUSED(ev);
398        if ( m_bIsMoving ) {    // fine dello spostamento dei pattern
399                AudioEngine::get_instance()->lock( RIGHT_HERE );
400                // create the new patterns
401
402                SE_movePatternCellAction *action = new SE_movePatternCellAction( m_movingCells, m_selectedCells , m_bIsCtrlPressed);
403                HydrogenApp::get_instance()->m_undoStack->push( action );
404
405        }
406
407        setCursor( QCursor( Qt::ArrowCursor ) );
408
409        m_bShowLasso = false;
410        m_bSequenceChanged = true;
411        m_bIsCtrlPressed = false;
412        update();
413}
414
415
416void SongEditor::movePatternCellAction( std::vector<QPoint> movingCells, std::vector<QPoint> selectedCells, bool bIsCtrlPressed, bool undo )
417{
418        Hydrogen *pEngine = Hydrogen::get_instance();
419
420        PatternList *pPatternList = pEngine->getSong()->get_pattern_list();
421        vector<PatternList*>* pColumns = pEngine->getSong()->get_pattern_group_vector();
422        for ( uint i = 0; i < movingCells.size(); i++ ) {
423                QPoint cell = movingCells[ i ];
424                if ( cell.x() < 0 || cell.y() < 0 || cell.y() >= (int)pPatternList->size() ) {
425                        // skip
426                        continue;
427                }
428                // aggiungo un pattern per volta
429                PatternList* pColumn = NULL;
430                if ( cell.x() < (int)pColumns->size() ) {
431                        pColumn = (*pColumns)[ cell.x() ];
432                }
433                else {
434                        // creo dei patternlist vuoti
435                        int nSpaces = cell.x() - pColumns->size();
436                        for ( int i = 0; i <= nSpaces; i++ ) {
437                                pColumn = new PatternList();
438                                pColumns->push_back( pColumn );
439                        }
440                }
441                pColumn->add( pPatternList->get( cell.y() ) );
442        }
443
444        if ( bIsCtrlPressed ) { // COPY
445                if ( undo )
446                        {
447                        // remove the old patterns
448                        for ( uint i = 0; i < selectedCells.size(); i++ ) {
449                                QPoint cell = selectedCells[ i ];
450                                PatternList* pColumn = NULL;
451                                if ( cell.x() < (int)pColumns->size() ) {
452                                        pColumn = (*pColumns)[ cell.x() ];
453                                }
454                                else {
455                                        pColumn = new PatternList();
456                                        pColumns->push_back( pColumn );
457                                }
458                                pColumn->del(pPatternList->get( cell.y() ) );
459                        }
460                        for ( uint i = 0; i < movingCells.size(); i++ ) {
461                                QPoint cell = movingCells[ i ];
462                                PatternList* pColumn = NULL;
463                                if ( cell.x() < (int)pColumns->size() ) {
464                                        pColumn = (*pColumns)[ cell.x() ];
465                                }
466                                else {
467                                        pColumn = new PatternList();
468                                        pColumns->push_back( pColumn );
469                                }
470                                pColumn->del(pPatternList->get( cell.y() ) );
471                        }
472                }
473        }
474        else {  // MOVE
475                // remove the old patterns
476                for ( uint i = 0; i < selectedCells.size(); i++ ) {
477                        QPoint cell = selectedCells[ i ];
478                        PatternList* pColumn = NULL;
479                        if ( cell.x() < (int)pColumns->size() ) {
480                                pColumn = (*pColumns)[ cell.x() ];
481                        }
482                        else {
483                                pColumn = new PatternList();
484                                pColumns->push_back( pColumn );
485                        }
486                        pColumn->del(pPatternList->get( cell.y() ) );
487                }
488        }
489
490        // remove the empty patternlist at the end of the song
491        for ( int i = pColumns->size() - 1; i != 0 ; i-- ) {
492                PatternList *pList = (*pColumns)[ i ];
493                int nSize = pList->size();
494                if ( nSize == 0 ) {
495                        pColumns->erase( pColumns->begin() + i );
496                        delete pList;
497                }
498                else {
499                        break;
500                }
501        }
502
503        pEngine->getSong()->__is_modified = true;
504        AudioEngine::get_instance()->unlock();
505
506        m_bIsMoving = false;
507        m_movingCells.clear();
508        m_selectedCells.clear();
509        m_bSequenceChanged = true;
510        update();
511}
512
513
514
515void SongEditor::paintEvent( QPaintEvent *ev )
516{
517/*      INFOLOG(
518                        "[paintEvent] x: " + to_string( ev->rect().x() ) +
519                        " y: " + to_string( ev->rect().y() ) +
520                        " w: " + to_string( ev->rect().width() ) +
521                        " h: " + to_string( ev->rect().height() )
522        );
523*/
524
525        // ridisegno tutto solo se sono cambiate le note
526        if (m_bSequenceChanged) {
527                m_bSequenceChanged = false;
528                drawSequence();
529        }
530
531        QPainter painter(this);
532        painter.drawPixmap( ev->rect(), *m_pSequencePixmap, ev->rect() );
533
534        if ( m_bShowLasso ) {
535                QPen pen( Qt::white );
536                pen.setStyle( Qt::DotLine );
537                painter.setPen( pen );
538                painter.drawRect( m_lasso );
539        }
540}
541
542
543
544void SongEditor::createBackground()
545{
546        UIStyle *pStyle = Preferences::get_instance()->getDefaultUIStyle();
547        QColor backgroundColor( pStyle->m_songEditor_backgroundColor.getRed(), pStyle->m_songEditor_backgroundColor.getGreen(), pStyle->m_songEditor_backgroundColor.getBlue() );
548        QColor alternateRowColor( pStyle->m_songEditor_alternateRowColor.getRed(), pStyle->m_songEditor_alternateRowColor.getGreen(), pStyle->m_songEditor_alternateRowColor.getBlue() );
549        QColor linesColor( pStyle->m_songEditor_lineColor.getRed(), pStyle->m_songEditor_lineColor.getGreen(), pStyle->m_songEditor_lineColor.getBlue() );
550
551        Hydrogen *pEngine = Hydrogen::get_instance();
552        Song *pSong = pEngine->getSong();
553
554        uint nPatterns = pSong->get_pattern_list()->size();
555
556        static int nOldHeight = -1;
557        int nNewHeight = m_nGridHeight * nPatterns;
558
559        if (nOldHeight != nNewHeight) {
560                // cambiamento di dimensioni...
561                if (nNewHeight == 0) {
562                        nNewHeight = 1; // the pixmap should not be empty
563                }
564
565                m_pBackgroundPixmap = new QPixmap( width(), nNewHeight );       // initialize the pixmap
566                m_pSequencePixmap = new QPixmap( width(), nNewHeight ); // initialize the pixmap
567                this->resize( QSize( width(), nNewHeight ) );
568        }
569
570        m_pBackgroundPixmap->fill( alternateRowColor );
571
572        QPainter p( m_pBackgroundPixmap );
573        p.setPen( linesColor );
574
575/*      // sfondo per celle scure (alternato)
576        for (uint i = 0; i < nPatterns; i++) {
577                if ( ( i % 2) != 0) {
578                        uint y = m_nGridHeight * i;
579                        p.fillRect ( 0, y, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
580                        p.fillRect ( 0, y + 2, m_nMaxPatternSequence * m_nGridWidth, m_nGridHeight - 4, alternateRowColor );
581                        p.fillRect ( 0, y + m_nGridHeight - 2, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
582                }
583        }
584*/
585        // celle...
586        p.setPen( linesColor );
587
588        // vertical lines
589        for (uint i = 0; i < m_nMaxPatternSequence + 1; i++) {
590                uint x = 10 + i * m_nGridWidth;
591                int x1 = x;
592                int x2 = x + m_nGridWidth;
593
594                p.drawLine( x1, 0, x1, m_nGridHeight * nPatterns );
595                p.drawLine( x2, 0, x2, m_nGridHeight * nPatterns );
596        }
597
598        p.setPen( linesColor );
599        // horizontal lines
600        for (uint i = 0; i < nPatterns; i++) {
601                uint y = m_nGridHeight * i;
602
603                int y1 = y + 2;
604                int y2 = y + m_nGridHeight - 2;
605
606                p.drawLine( 0, y1, (m_nMaxPatternSequence * m_nGridWidth), y1 );
607                p.drawLine( 0, y2, (m_nMaxPatternSequence * m_nGridWidth), y2 );
608        }
609
610
611        p.setPen( backgroundColor );
612        // horizontal lines (erase..)
613        for (uint i = 0; i < nPatterns + 1; i++) {
614                uint y = m_nGridHeight * i;
615
616                p.fillRect( 0, y, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
617                p.drawLine( 0, y + m_nGridHeight - 1, m_nMaxPatternSequence * m_nGridWidth, y + m_nGridHeight - 1 );
618        }
619
620        //~ celle
621        m_bSequenceChanged = true;
622}
623
624void SongEditor::cleanUp(){
625
626        delete m_pBackgroundPixmap;
627        delete m_pSequencePixmap;
628}
629
630void SongEditor::drawSequence()
631{
632        QPainter p;
633        p.begin( m_pSequencePixmap );
634        p.drawPixmap( rect(), *m_pBackgroundPixmap, rect() );
635        p.end();
636
637        Song* song = Hydrogen::get_instance()->getSong();
638        PatternList *patList = song->get_pattern_list();
639        vector<PatternList*>* pColumns = song->get_pattern_group_vector();
640        uint listLength = patList->size();
641        for (uint i = 0; i < pColumns->size(); i++) {
642                PatternList* pColumn = (*pColumns)[ i ];
643               
644                std::set<Pattern*> drawnAsVirtual;
645
646                for (uint nPat = 0; nPat < pColumn->size(); ++nPat) {
647                        H2Core::Pattern *pat = pColumn->get( nPat );
648
649                        if (drawnAsVirtual.find(pat) == drawnAsVirtual.end()) {
650                            int position = -1;
651                            // find the position in pattern list
652                            for (uint j = 0; j < listLength; j++) {
653                                    H2Core::Pattern *pat2 = patList->get( j );
654                                    if (pat == pat2) {
655                                            position = j;
656                                            break;
657                                    }
658                            }
659                            if (position == -1) {
660                                    WARNINGLOG( QString("[drawSequence] position == -1, group = %1").arg( i ) );
661                            }
662                            drawPattern( i, position, false );
663                        }//if
664                       
665                        for (std::set<Pattern*>::const_iterator virtualIter = pat->virtual_pattern_transitive_closure_set.begin(); virtualIter != pat->virtual_pattern_transitive_closure_set.end(); ++virtualIter) {
666                            if (drawnAsVirtual.find(*virtualIter) == drawnAsVirtual.end()) {
667                                int position = -1;
668                                // find the position in pattern list
669                                for (uint j = 0; j < listLength; j++) {
670                                    H2Core::Pattern *pat2 = patList->get( j );
671                                    if (*virtualIter == pat2) {
672                                            position = j;
673                                            break;
674                                    }//if
675                                }//for
676                                if (position == -1) {
677                                    WARNINGLOG( QString("[drawSequence] position == -1, group = %1").arg( i ) );
678                                }
679                                drawPattern( i, position, true );
680                               
681                                drawnAsVirtual.insert(*virtualIter);
682                            }//if
683                        }//for
684                }
685        }
686
687        // Moving cells
688        p.begin( m_pSequencePixmap );
689//      p.setRasterOp( Qt::XorROP );
690
691// comix: this composition mode seems to be not available on Mac
692        p.setCompositionMode( QPainter::CompositionMode_Xor );
693        QPen pen( Qt::gray );
694        pen.setStyle( Qt::DotLine );
695        p.setPen( pen );
696        for ( uint i = 0; i < m_movingCells.size(); i++ ) {
697                int x = 10 + m_nGridWidth * ( m_movingCells[ i ] ).x();
698                int y = m_nGridHeight * ( m_movingCells[ i ] ).y();
699
700                QColor patternColor;
701                patternColor.setRgb( 255, 255, 255 );
702                p.fillRect( x + 2, y + 4, m_nGridWidth - 3, m_nGridHeight - 7, patternColor );
703        }
704
705}
706
707
708
709void SongEditor::drawPattern( int pos, int number, bool invertColour )
710{
711        Preferences *pref = Preferences::get_instance();
712        UIStyle *pStyle = pref->getDefaultUIStyle();
713        QPainter p( m_pSequencePixmap );
714        QColor patternColor( pStyle->m_songEditor_pattern1Color.getRed(), pStyle->m_songEditor_pattern1Color.getGreen(), pStyle->m_songEditor_pattern1Color.getBlue() );
715       
716        if (true == invertColour) {
717            patternColor = patternColor.darker(200);
718        }//if
719
720        bool bIsSelected = false;
721        for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
722                QPoint point = m_selectedCells[ i ];
723                if ( point.x() == pos && point.y() == number ) {
724                        bIsSelected = true;
725                        break;
726                }
727        }
728
729        if ( bIsSelected ) {
730                patternColor = patternColor.dark( 130 );
731        }
732
733        int x = 10 + m_nGridWidth * pos;
734        int y = m_nGridHeight * number;
735
736//      p.setPen( patternColor.light( 120 ) );  // willie - For the bevel - haven't yet figured how it's supposed to work...
737        p.fillRect( x + 1, y + 3, m_nGridWidth - 1, m_nGridHeight - 5, patternColor );
738}
739
740
741void SongEditor::clearThePatternSequenseVector( QString filename )
742{
743        Hydrogen *engine = Hydrogen::get_instance();
744
745        AudioEngine::get_instance()->lock( RIGHT_HERE );
746
747        Song *song = engine->getSong();
748
749        //before delet the sequense, write a temp seqense file to disk
750        LocalFileMng fileMng;
751        int err = fileMng.writeTempPatternList( song , filename);
752
753        vector<PatternList*> *pPatternGroupsVect = song->get_pattern_group_vector();
754        for (uint i = 0; i < pPatternGroupsVect->size(); i++) {
755                PatternList *pPatternList = (*pPatternGroupsVect)[i];
756                pPatternList->clear();
757                delete pPatternList;
758        }
759        pPatternGroupsVect->clear();
760
761        song->__is_modified = true;
762        AudioEngine::get_instance()->unlock();
763        m_bSequenceChanged = true;
764        update();
765}
766
767void SongEditor::updateEditorandSetTrue()
768{
769        Hydrogen::get_instance()->getSong()->__is_modified = true;
770        m_bSequenceChanged = true;
771        update();
772}
773// :::::::::::::::::::
774
775
776const char* SongEditorPatternList::__class_name = "SongEditorPatternList";
777
778SongEditorPatternList::SongEditorPatternList( QWidget *parent )
779 : QWidget( parent )
780 , Object( __class_name )
781 , EventListener()
782 , m_pBackgroundPixmap( NULL )
783{
784        m_nWidth = 200;
785        m_nGridHeight = 18;
786        setAttribute(Qt::WA_NoBackground);
787       
788        setAcceptDrops(true);
789
790        patternBeingEdited = NULL;
791       
792        line = new QLineEdit( "Inline Pattern Name", this );
793        line->setFrame( false );
794        line->hide();
795        connect( line, SIGNAL(editingFinished()), this, SLOT(inlineEditingFinished()) );
796        connect( line, SIGNAL(returnPressed()), this, SLOT(inlineEditingEntered()) );
797
798        this->resize( m_nWidth, m_nInitialHeight );
799
800        m_labelBackgroundLight.load( Skin::getImagePath() + "/songEditor/songEditorLabelBG.png" );
801        m_labelBackgroundDark.load( Skin::getImagePath() + "/songEditor/songEditorLabelABG.png" );
802        m_labelBackgroundSelected.load( Skin::getImagePath() + "/songEditor/songEditorLabelSBG.png" );
803        m_playingPattern_on_Pixmap.load( Skin::getImagePath() + "/songEditor/playingPattern_on.png" );
804        m_playingPattern_off_Pixmap.load( Skin::getImagePath() + "/songEditor/playingPattern_off.png" );
805
806        m_pPatternPopup = new QMenu( this );
807        //m_pPatternPopup->addAction( trUtf8("Edit"),  this, SLOT( patternPopup_edit() ) );obsolete in >=0.9.4, because the patterneditor switch by clicking an each item to the corresponding pattern
808        m_pPatternPopup->addAction( trUtf8("Copy"),  this, SLOT( patternPopup_copy() ) );
809        m_pPatternPopup->addAction( trUtf8("Delete"),  this, SLOT( patternPopup_delete() ) );
810        m_pPatternPopup->addAction( trUtf8("Fill/Clear ..."),  this, SLOT( patternPopup_fill() ) );
811        m_pPatternPopup->addAction( trUtf8("Properties"),  this, SLOT( patternPopup_properties() ) );
812        m_pPatternPopup->addAction( trUtf8("Load Pattern"),  this, SLOT( patternPopup_load() ) );
813        m_pPatternPopup->addAction( trUtf8("Save Pattern"),  this, SLOT( patternPopup_save() ) );
814        m_pPatternPopup->addAction( trUtf8("Virtual Pattern"), this, SLOT( patternPopup_virtualPattern() ) );
815
816        HydrogenApp::get_instance()->addEventListener( this );
817
818        createBackground();
819        update();
820}
821
822
823
824SongEditorPatternList::~SongEditorPatternList()
825{
826}
827
828
829void SongEditorPatternList::patternChangedEvent() {
830
831        createBackground();
832        update();
833        ///here we check the timeline  && m_pSong->get_mode() == Song::SONG_MODE
834        Hydrogen *engine = Hydrogen::get_instance();
835        if ( ( Preferences::get_instance()->__usetimeline ) && ( engine->getSong()->get_mode() == Song::SONG_MODE ) ){
836                for ( int i = 0; i < static_cast<int>(engine->m_timelinevector.size()); i++){
837                        if ( ( engine->m_timelinevector[i].m_htimelinebeat == engine->getPatternPos() )
838                                && ( engine->getNewBpmJTM() != engine->m_timelinevector[i].m_htimelinebpm ) ){
839                                engine->setBPM( engine->m_timelinevector[i].m_htimelinebpm );
840                        }//if
841                }//for
842        }//if
843}
844
845
846/// Single click, select the next pattern
847void SongEditorPatternList::mousePressEvent( QMouseEvent *ev )
848{
849        int row = (ev->y() / m_nGridHeight);
850
851        Hydrogen *engine = Hydrogen::get_instance();
852        Song *song = engine->getSong();
853        PatternList *patternList = song->get_pattern_list();
854
855        if ( row >= (int)patternList->size() ) {
856                return;
857        }
858
859        if ( (ev->button() == Qt::MidButton) || (ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::RightButton) || (ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::LeftButton) ){
860                togglePattern( row );
861        } else {
862                engine->setSelectedPatternNumber( row );
863                if (ev->button() == Qt::RightButton)  {
864        /*
865                        if ( song->getMode() == Song::PATTERN_MODE ) {
866       
867                                PatternList *pCurrentPatternList = engine->getCurrentPatternList();
868                                if ( pCurrentPatternList->size() == 0 ) {
869                                        // nessun pattern e' attivo. seleziono subito questo.
870                                        pCurrentPatternList->add( patternList->get( row ) );
871                                }
872                                else {
873                                        engine->setNextPattern( row );
874                                }
875                        }
876        */
877                        m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
878                }
879        }
880
881        createBackground();
882        update();
883}
884
885
886///
887/// Start/stop playing a pattern in "pattern mode"
888///
889void SongEditorPatternList::togglePattern( int row ) {
890
891        Hydrogen *engine = Hydrogen::get_instance();
892/*      Song *song = engine->getSong();
893        PatternList *patternList = song->get_pattern_list();*/
894
895//      PatternList *pCurrentPatternList = engine->getCurrentPatternList();
896
897//      bool isPatternPlaying = false;
898        engine->sequencer_setNextPattern( row, false, true );
899
900//      for ( uint i = 0; i < pCurrentPatternList->size(); ++i ) {
901//              if ( pCurrentPatternList->get( i ) == patternList->get( row ) ) {
902//                      // the pattern is already playing, stop it!
903//                      isPatternPlaying = true;
904//                      break;
905//              }
906//      }
907//
908//      if ( isPatternPlaying ) {
909//              //pCurrentPatternList->del( patternList->get( row ) );
910//              engine->sequencer_setNextPattern( row, false, true );   // remove from the playing pattern list
911//      }
912//      else {
913//              // the pattern is not playing, add it to the list
914//              //pCurrentPatternList->add( patternList->get( row ) );
915//              engine->sequencer_setNextPattern( row, true, false );   // add to the playing pattern list
916//      }
917
918        createBackground();
919        update();
920}
921
922
923void SongEditorPatternList::mouseDoubleClickEvent( QMouseEvent *ev )
924{
925        int row = (ev->y() / m_nGridHeight);
926        inlineEditPatternName( row );
927}
928
929void SongEditorPatternList::inlineEditPatternName( int row )
930{
931        Hydrogen *engine = Hydrogen::get_instance();
932        Song *song = engine->getSong();
933        PatternList *patternList = song->get_pattern_list();
934
935        if ( row >= (int)patternList->size() ) {
936                return;
937        }
938        patternBeingEdited = patternList->get( row );
939        line->setGeometry( 23, row * m_nGridHeight , m_nWidth - 23, m_nGridHeight  );
940        line->setText( patternBeingEdited->get_name() );
941        line->selectAll();
942        line->show();
943        line->setFocus();
944}
945
946void SongEditorPatternList::inlineEditingEntered()
947{
948        assert( patternBeingEdited != NULL );
949        if ( PatternPropertiesDialog::nameCheck( line->text() ) )
950        {       
951                Hydrogen *pEngine = Hydrogen::get_instance();
952                int nSelectedPattern = pEngine->getSelectedPatternNumber();
953
954                SE_modifyPatternPropertiesAction *action = new SE_modifyPatternPropertiesAction(  patternBeingEdited->get_name() , patternBeingEdited->get_category(),
955                                                                                                  line->text(), patternBeingEdited->get_category(), nSelectedPattern );
956                HydrogenApp::get_instance()->m_undoStack->push( action );
957        }
958//      patternBeingEdited = NULL;
959}
960
961
962void SongEditorPatternList::inlineEditingFinished()
963{
964        patternBeingEdited = NULL;
965        line->hide();
966}
967
968
969void SongEditorPatternList::paintEvent( QPaintEvent *ev )
970{
971        QPainter painter(this);
972        painter.drawPixmap( ev->rect(), *m_pBackgroundPixmap, ev->rect() );
973}
974
975
976
977void SongEditorPatternList::updateEditor()
978{
979        if(!isVisible()) {
980                return;
981        }
982
983        update();
984}
985
986
987
988void SongEditorPatternList::createBackground()
989{
990        Preferences *pref = Preferences::get_instance();
991        UIStyle *pStyle = pref->getDefaultUIStyle();
992        QColor textColor( pStyle->m_songEditor_textColor.getRed(), pStyle->m_songEditor_textColor.getGreen(), pStyle->m_songEditor_textColor.getBlue() );
993
994        QString family = pref->getApplicationFontFamily();
995        int size = pref->getApplicationFontPointSize();
996        QFont textFont( family, size );
997
998        QFont boldTextFont( textFont);
999        boldTextFont.setPointSize(10);
1000        boldTextFont.setBold( true );
1001
1002        Hydrogen *pEngine = Hydrogen::get_instance();
1003        Song *pSong = pEngine->getSong();
1004        int nPatterns = pSong->get_pattern_list()->size();
1005        int nSelectedPattern = pEngine->getSelectedPatternNumber();
1006
1007        static int oldHeight = -1;
1008        int newHeight = m_nGridHeight * nPatterns;
1009
1010        if (oldHeight != newHeight) {
1011                if (newHeight == 0) {
1012                        newHeight = 1;  // the pixmap should not be empty
1013                }
1014                delete m_pBackgroundPixmap;
1015                m_pBackgroundPixmap = new QPixmap( m_nWidth, newHeight );       // initialize the pixmap
1016                this->resize( m_nWidth, newHeight );
1017        }
1018        m_pBackgroundPixmap->fill( Qt::black );
1019
1020        QPainter p( m_pBackgroundPixmap );
1021        p.setFont( boldTextFont );
1022
1023        for ( int i = 0; i < nPatterns; i++ ) {
1024                uint y = m_nGridHeight * i;
1025                if ( i == nSelectedPattern ) {
1026                        p.drawPixmap( QPoint( 0, y ), m_labelBackgroundSelected );
1027                }
1028                else {
1029                        if ( ( i % 2) == 0 ) {
1030                                p.drawPixmap( QPoint( 0, y ), m_labelBackgroundDark );
1031                        }
1032                        else {
1033                                p.drawPixmap( QPoint( 0, y ), m_labelBackgroundLight );
1034                        }
1035                }
1036        }
1037
1038        PatternList *pCurrentPatternList = pEngine->getCurrentPatternList();
1039
1040        /// paint the foreground (pattern name etc.)
1041        for ( int i = 0; i < nPatterns; i++ ) {
1042                H2Core::Pattern *pPattern = pSong->get_pattern_list()->get(i);
1043                //uint y = m_nGridHeight * i;
1044
1045                // Text
1046                bool bNext = false, bActive = false;
1047/*              for (uint j = 0; j < pCurrentPatternList->size(); j++) {
1048                        if ( pPattern == pCurrentPatternList->get(j) ) {
1049                                bActive = true;
1050                                break;
1051                        }
1052                }*/
1053                if ( pCurrentPatternList->index( pPattern ) != -1 ) bActive = true;
1054                if ( pEngine->getNextPatterns()->index( pPattern ) != -1 ) bNext = true;
1055
1056                if ( i == nSelectedPattern ) {
1057                        p.setPen( QColor( 0,0,0 ) );
1058                }
1059                else {
1060                        p.setPen( textColor );
1061                }
1062
1063                uint text_y = i * m_nGridHeight;
1064                if ( bNext ) {
1065                        p.drawPixmap( QPoint( 5, text_y + 3 ), m_playingPattern_off_Pixmap );
1066                }
1067                else if (bActive) {
1068//                      p.drawText( 5, text_y - 1 - m_nGridHeight, m_nWidth - 25, m_nGridHeight + 2, Qt::AlignVCenter, ">" );
1069               
1070                        //mark active pattern with triangular
1071                        if( ! pref->patternModePlaysSelected() ){
1072                                p.drawPixmap( QPoint( 5, text_y + 3 ), m_playingPattern_on_Pixmap );
1073                        }
1074                }
1075
1076
1077                p.drawText( 25, text_y - 1, m_nWidth - 25, m_nGridHeight + 2, Qt::AlignVCenter, pPattern->get_name() );
1078        }
1079
1080}
1081
1082
1083void SongEditorPatternList::patternPopup_virtualPattern()
1084{
1085    Hydrogen *pEngine = Hydrogen::get_instance();
1086    int nSelectedPattern = pEngine->getSelectedPatternNumber();
1087    VirtualPatternDialog *dialog = new VirtualPatternDialog( this );
1088    SongEditorPanel *pSEPanel = HydrogenApp::get_instance()->getSongEditorPanel();
1089    int tmpselectedpatternpos = pEngine->getSelectedPatternNumber();   
1090
1091    dialog->patternList->setSortingEnabled(1);
1092   
1093    Song *song = pEngine->getSong();
1094    PatternList *pPatternList = song->get_pattern_list();
1095    H2Core::Pattern *selectedPattern = pPatternList->get(tmpselectedpatternpos);
1096   
1097    std::map<QString, Pattern*> patternNameMap;
1098   
1099    int listsize = pPatternList->size();
1100    for (unsigned int index = 0; index < listsize; ++index) {
1101        H2Core::Pattern *curPattern = pPatternList->get( index );
1102        QString patternName = curPattern->get_name();
1103       
1104        if (patternName == selectedPattern->get_name()) {
1105            continue;
1106        }//if
1107       
1108        patternNameMap[patternName] = curPattern;
1109       
1110        QListWidgetItem *newItem = new QListWidgetItem(patternName, dialog->patternList);
1111        dialog->patternList->insertItem(0, newItem );
1112       
1113        if (selectedPattern->virtual_pattern_set.find(curPattern) != selectedPattern->virtual_pattern_set.end()) {
1114            dialog->patternList->setItemSelected(newItem, true);
1115        }//if
1116    }//for
1117   
1118    if ( dialog->exec() == QDialog::Accepted ) {
1119        selectedPattern->virtual_pattern_set.clear();
1120        for (unsigned int index = 0; index < listsize-1; ++index) {
1121            QListWidgetItem *listItem = dialog->patternList->item(index);
1122            if (dialog->patternList->isItemSelected(listItem) == true) {
1123                if (patternNameMap.find(listItem->text()) != patternNameMap.end()) {
1124                    selectedPattern->virtual_pattern_set.insert(patternNameMap[listItem->text()]);
1125                }//if
1126            }//if
1127        }//for
1128       
1129        pSEPanel->updateAll();
1130    }//if
1131   
1132    dialog->computeVirtualPatternTransitiveClosure(pPatternList);
1133
1134    delete dialog;
1135}//patternPopup_virtualPattern
1136
1137
1138
1139void SongEditorPatternList::patternPopup_load()
1140{
1141
1142        Hydrogen *engine = Hydrogen::get_instance();
1143        int tmpselectedpatternpos = engine->getSelectedPatternNumber();
1144
1145        Song *song = engine->getSong();
1146        Pattern *pat = song->get_pattern_list()->get( tmpselectedpatternpos );
1147
1148        QString oldPatternName = pat->get_name();
1149
1150        QDir dirPattern( Preferences::get_instance()->getDataDirectory() + "/patterns" );
1151        std::auto_ptr<QFileDialog> fd( new QFileDialog );
1152        fd->setFileMode(QFileDialog::ExistingFile);
1153        fd->setFilter( trUtf8("Hydrogen Pattern (*.h2pattern)") );
1154        fd->setDirectory(dirPattern );
1155
1156        fd->setWindowTitle( trUtf8( "Open Pattern" ) );
1157
1158        QString filename;
1159        if (fd->exec() == QDialog::Accepted) {
1160                filename = fd->selectedFiles().first();
1161        }
1162        else
1163        {
1164                return;
1165        }
1166
1167        //create a unique sequencefilename
1168        time_t thetime;
1169        thetime = time(NULL);
1170        QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" );
1171        SE_loadPatternAction *action = new SE_loadPatternAction(  filename, oldPatternName, sequenceFileName, tmpselectedpatternpos );
1172        HydrogenApp::get_instance()->m_undoStack->push( action );
1173
1174       
1175
1176}
1177
1178void SongEditorPatternList::loadPatternAction( QString afilename, int position)
1179{
1180        Hydrogen *engine = Hydrogen::get_instance();
1181        Song *song = engine->getSong();
1182        PatternList *pPatternList = song->get_pattern_list();
1183
1184        LocalFileMng mng;
1185        LocalFileMng fileMng;
1186        Pattern* err = fileMng.loadPattern( afilename );
1187        if ( err == 0 ) {
1188                _ERRORLOG( "Error loading the pattern" );
1189        }else{
1190                H2Core::Pattern *pNewPattern = err;
1191                pPatternList->add( pNewPattern );
1192                for (int nPatr = pPatternList->size() +1 ; nPatr >= position; nPatr--) {
1193                        H2Core::Pattern *pPattern = pPatternList->get(nPatr - 1);
1194                        pPatternList->replace( nPatr, pPattern );
1195                }
1196                pPatternList->replace( position, pNewPattern );
1197
1198                engine->setSelectedPatternNumber( position );
1199                song->__is_modified = true;
1200                createBackground();
1201                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1202        }
1203
1204}
1205
1206
1207void SongEditorPatternList::patternPopup_save()
1208{       
1209        Hydrogen *engine = Hydrogen::get_instance();
1210        int nSelectedPattern = engine->getSelectedPatternNumber();
1211        Song *song = engine->getSong();
1212        Pattern *pat = song->get_pattern_list()->get( nSelectedPattern );
1213
1214        QString patternname = pat->get_name();
1215
1216        LocalFileMng fileMng;
1217        int err = fileMng.savePattern( song, engine->getCurrentDrumkitname(), nSelectedPattern, patternname, patternname, 1 );
1218        if ( err == 1 ) {
1219                int res = QMessageBox::information( this, "Hydrogen", tr( "The pattern-file exists. \nOverwrite the existing pattern?"), tr("&Ok"), tr("&Cancel"), 0, 1 );
1220                if ( res == 0 ) {
1221                        int err2 = fileMng.savePattern( song, engine->getCurrentDrumkitname(), nSelectedPattern, patternname, patternname, 3 );
1222                        if( err2 == 1){
1223                                _ERRORLOG( "Error saving the pattern" );
1224                                return;
1225                        } //if err2
1226                }else{ // res cancel
1227                        return;
1228                } //if res     
1229        } //if err
1230       
1231
1232#ifdef WIN32
1233        Sleep ( 10 );
1234#else
1235        usleep ( 10000 );
1236#endif
1237        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->test_expandedItems();
1238        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->updateDrumkitList();
1239}
1240
1241
1242
1243void SongEditorPatternList::patternPopup_edit()
1244{
1245        HydrogenApp::get_instance()->getPatternEditorPanel()->show();
1246        HydrogenApp::get_instance()->getPatternEditorPanel()->setFocus();
1247}
1248
1249
1250
1251void SongEditorPatternList::patternPopup_properties()
1252{
1253        Hydrogen *engine = Hydrogen::get_instance();
1254        Song *song = engine->getSong();
1255        PatternList *patternList = song->get_pattern_list();
1256
1257        int nSelectedPattern = engine->getSelectedPatternNumber();
1258        H2Core::Pattern *pattern = patternList->get( nSelectedPattern );
1259
1260        PatternPropertiesDialog *dialog = new PatternPropertiesDialog(this, pattern, nSelectedPattern, false);
1261        if ( dialog->exec() == QDialog::Accepted );
1262        delete dialog;
1263        dialog = NULL;
1264}
1265
1266
1267void SongEditorPatternList::acceptPatternPropertiesDialogSettings(QString newPatternName, QString newPatternCategory, int patternNr)
1268{
1269        Hydrogen *engine = Hydrogen::get_instance();
1270        Song *song = engine->getSong();
1271        PatternList *patternList = song->get_pattern_list();
1272        H2Core::Pattern *pattern = patternList->get( patternNr );
1273        pattern->set_name( newPatternName );
1274        pattern->set_category( newPatternCategory );
1275        song->__is_modified = true;
1276        EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
1277        createBackground();
1278        update();
1279}
1280
1281
1282void SongEditorPatternList::revertPatternPropertiesDialogSettings(QString oldPatternName, QString oldPatternCategory, int patternNr)
1283{
1284        Hydrogen *engine = Hydrogen::get_instance();
1285        Song *song = engine->getSong();
1286        PatternList *patternList = song->get_pattern_list();
1287        H2Core::Pattern *pattern = patternList->get( patternNr );
1288        pattern->set_name( oldPatternName );
1289        pattern->set_category( oldPatternCategory );
1290        song->__is_modified = true;
1291        EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
1292        createBackground();
1293        update();
1294}
1295
1296
1297void SongEditorPatternList::patternPopup_delete()
1298{
1299
1300        Hydrogen *pEngine = Hydrogen::get_instance();
1301        Song *song = pEngine->getSong();
1302        PatternList *pSongPatternList = song->get_pattern_list();
1303        int patternPosition = pEngine->getSelectedPatternNumber();
1304
1305        //create a unique sequencefilename
1306        time_t thetime;
1307        thetime = time(NULL);
1308        QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" );
1309
1310        //create a unique patternfilename
1311        QString patternFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "PAT.xml" );
1312
1313        SE_deletePatternFromListAction *action = new    SE_deletePatternFromListAction( patternFilename , sequenceFileName, patternPosition );
1314        HydrogenApp::get_instance()->m_undoStack->push( action );
1315
1316}
1317
1318
1319void SongEditorPatternList::deletePatternFromList( QString patternFilename, QString sequenceFileName, int patternPosition )
1320{
1321
1322        Hydrogen *pEngine = Hydrogen::get_instance();
1323
1324        if ( pEngine->getSong()->get_mode() == Song::PATTERN_MODE ) {
1325                pEngine->sequencer_setNextPattern( -1, false, false );  // reimposto il prossimo pattern a NULL, altrimenti viene scelto quello che sto distruggendo ora...
1326        }
1327
1328        Song *song = pEngine->getSong();
1329        PatternList *pSongPatternList = song->get_pattern_list();
1330
1331
1332        //write sequence to disk
1333        //this is important because parts of the sequese will remove after deleting a pattern
1334        LocalFileMng fileMng;
1335        int errseq = fileMng.writeTempPatternList( song , sequenceFileName);
1336       
1337        //write pattern to disk;
1338        Pattern *pat = song->get_pattern_list()->get( patternPosition );
1339
1340        QString patternname = pat->get_name();
1341        int err =1;
1342        err = fileMng.savePattern( song, pEngine->getCurrentDrumkitname(), patternPosition, patternFilename, patternname, 4 );
1343
1344#ifdef WIN32
1345        Sleep ( 10 );
1346#else
1347        usleep ( 10000 );
1348#endif
1349        //~save pattern end
1350
1351        H2Core::Pattern *pattern = pSongPatternList->get( patternPosition );
1352        INFOLOG( QString("[patternPopup_delete] Delete pattern: %1 @%2").arg(pattern->get_name()).arg( (long)pattern ) );
1353        pSongPatternList->del(pattern);
1354
1355        vector<PatternList*> *patternGroupVect = song->get_pattern_group_vector();
1356
1357        uint i = 0;
1358        while (i < patternGroupVect->size() ) {
1359                PatternList *list = (*patternGroupVect)[i];
1360
1361                uint j = 0;
1362                while ( j < list->size() ) {
1363                        H2Core::Pattern *pOldPattern = list->get( j );
1364                        if (pOldPattern == pattern ) {
1365                                list->del( j );
1366                                continue;
1367                        }
1368                        j++;
1369                }
1370                i++;
1371
1372        }
1373
1374
1375        PatternList *list = pEngine->getCurrentPatternList();
1376        list->del( pattern );
1377        // se esiste, seleziono il primo pattern
1378        if ( pSongPatternList->size() > 0 ) {
1379                H2Core::Pattern *pFirstPattern = pSongPatternList->get( 0 );
1380                list->add( pFirstPattern );
1381                // Cambio due volte...cosi' il pattern editor viene costretto ad aggiornarsi
1382                pEngine->setSelectedPatternNumber( -1 );
1383                pEngine->setSelectedPatternNumber( 0 );
1384        }
1385        else {
1386                // there's no patterns..       
1387                Pattern *emptyPattern = Pattern::get_empty_pattern();
1388                emptyPattern->set_name( trUtf8("Pattern 1") );
1389                emptyPattern->set_category( trUtf8("not_categorized") );
1390                pSongPatternList->add( emptyPattern );
1391                pEngine->setSelectedPatternNumber( -1 );
1392                pEngine->setSelectedPatternNumber( 0 );
1393        }
1394       
1395        for (unsigned int index = 0; index < pSongPatternList->size(); ++index) {
1396            H2Core::Pattern *curPattern = pSongPatternList->get(index);
1397           
1398            std::set<Pattern*>::iterator virtIter = curPattern->virtual_pattern_set.find(pattern);
1399            if (virtIter != curPattern->virtual_pattern_set.end()) {
1400                curPattern->virtual_pattern_set.erase(virtIter);
1401            }//if
1402        }//for
1403
1404        VirtualPatternDialog::computeVirtualPatternTransitiveClosure(pSongPatternList);
1405
1406        delete pattern;
1407        song->__is_modified = true;
1408        HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1409
1410}
1411
1412void SongEditorPatternList::restoreDeletedPatternsFromList( QString patternFilename, QString sequenceFileName, int patternPosition  )
1413{
1414
1415        Hydrogen *engine = Hydrogen::get_instance();
1416        int tmpselectedpatternpos = patternPosition;
1417        Song *song = engine->getSong();
1418        PatternList *pPatternList = song->get_pattern_list();
1419
1420
1421        LocalFileMng mng;
1422        LocalFileMng fileMng;
1423        Pattern* err = fileMng.loadPattern( patternFilename );
1424        if ( err == 0 ) {
1425                _ERRORLOG( "Error loading the pattern" );
1426        }else{
1427                H2Core::Pattern *pNewPattern = err;
1428                pPatternList->add( pNewPattern );
1429
1430                for (int nPatr = pPatternList->size() +1 ; nPatr >= tmpselectedpatternpos; nPatr--) {
1431                        H2Core::Pattern *pPattern = pPatternList->get(nPatr - 1);
1432                        pPatternList->replace( nPatr, pPattern );
1433                }
1434
1435                pPatternList->replace( tmpselectedpatternpos, pNewPattern );
1436                song->__is_modified = true;
1437                createBackground();
1438                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1439                EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );   
1440        }
1441
1442}
1443
1444
1445void SongEditorPatternList::patternPopup_copy()
1446{
1447        Hydrogen *pEngine = Hydrogen::get_instance();
1448        Song *pSong = pEngine->getSong();
1449        PatternList *pPatternList = pSong->get_pattern_list();
1450        int nSelectedPattern = pEngine->getSelectedPatternNumber();
1451        H2Core::Pattern *pPattern = pPatternList->get( nSelectedPattern );
1452
1453        //create a tmp pattern needed for PatternPropertiesDialog.
1454        H2Core::Pattern *pNewPattern = pPattern->copy();
1455        pPatternList->add( pNewPattern );
1456
1457        // rename the copied pattern
1458        PatternPropertiesDialog *dialog = new PatternPropertiesDialog( this, pNewPattern, nSelectedPattern, true );
1459        if ( dialog->exec() == QDialog::Accepted ) {
1460
1461                time_t thetime;
1462                thetime = time(NULL);
1463                //create a unique patternfilename
1464                QString patternFilename = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "PAT.xml" );
1465                LocalFileMng fileMng;
1466                int err =1;
1467                err = fileMng.savePattern( pSong, pEngine->getCurrentDrumkitname(), pPatternList->size() -1 , patternFilename, pNewPattern->get_name(), 4 );
1468
1469                SE_copyPatternAction *action = new SE_copyPatternAction( patternFilename ,nSelectedPattern + 1 );
1470                HydrogenApp::get_instance()->m_undoStack->push( action );
1471        }
1472       
1473        //delete the tmp pattern
1474        pPatternList->del( pNewPattern );
1475        delete pNewPattern;
1476       
1477        delete dialog;
1478
1479        HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1480}
1481
1482
1483void SongEditorPatternList::patternPopup_copyAction( QString patternFilename, int patternposition )
1484{
1485       
1486        Hydrogen *engine = Hydrogen::get_instance();
1487        Song *song = engine->getSong();
1488        PatternList *pPatternList = song->get_pattern_list();
1489
1490        LocalFileMng mng;
1491        LocalFileMng fileMng;
1492        Pattern* err = fileMng.loadPattern( patternFilename );
1493        if ( err == 0 ) {
1494                _ERRORLOG( "Error loading the pattern" );
1495        }else{
1496                H2Core::Pattern *pNewPattern = err;
1497                pPatternList->add( pNewPattern );
1498
1499                for (int nPatr = pPatternList->size() +1 ; nPatr >= patternposition; nPatr--) {
1500                        H2Core::Pattern *pPattern = pPatternList->get(nPatr - 1);
1501                        pPatternList->replace( nPatr, pPattern );
1502                }
1503                pPatternList->replace( patternposition, pNewPattern );
1504                engine->setSelectedPatternNumber( patternposition );
1505
1506                song->__is_modified = true;
1507                createBackground();
1508                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1509                EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
1510        }
1511
1512}
1513
1514void SongEditorPatternList::patternPopup_fill()
1515{
1516        Hydrogen *pEngine = Hydrogen::get_instance();
1517        int nSelectedPattern = pEngine->getSelectedPatternNumber();
1518        FillRange range;
1519        PatternFillDialog *dialog = new PatternFillDialog( this, &range );
1520
1521        // use a PatternFillDialog to get the range and mode data
1522        if ( dialog->exec() == QDialog::Accepted ) {
1523
1524                SE_fillRangePatternAction *action = new SE_fillRangePatternAction( &range, nSelectedPattern );
1525                HydrogenApp::get_instance()->m_undoStack->push( action );
1526        }
1527
1528        delete dialog;
1529
1530}
1531
1532
1533void SongEditorPatternList::fillRangeWithPattern( FillRange* pRange, int nPattern )
1534{
1535        Hydrogen *pEngine = Hydrogen::get_instance();
1536        AudioEngine::get_instance()->lock( RIGHT_HERE );
1537
1538
1539        Song *pSong = pEngine->getSong();
1540        PatternList *pPatternList = pSong->get_pattern_list();
1541        H2Core::Pattern *pPattern = pPatternList->get( nPattern );
1542        vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();     // E' la lista di "colonne" di pattern
1543        PatternList *pColumn;
1544
1545        int nColumn, nColumnIndex;
1546        bool bHasPattern = false;
1547        int fromVal = pRange->fromVal - 1;
1548        int toVal   = pRange->toVal;
1549
1550
1551
1552        // Add patternlists to PatternGroupVector as necessary
1553
1554        int nDelta = toVal - pColumns->size() + 1;
1555
1556        for ( int i = 0; i < nDelta; i++ ) {
1557                pColumn = new PatternList();
1558                pColumns->push_back( pColumn );
1559        }
1560
1561
1562        // Fill or Clear each cell in range
1563
1564        for ( nColumn = fromVal; nColumn < toVal; nColumn++ ) {
1565
1566                // expand Pattern
1567                pColumn = ( *pColumns )[ nColumn ];
1568
1569                bHasPattern = false;
1570
1571                // check whether the pattern (and column) already exists
1572                for ( nColumnIndex = 0; pColumn && nColumnIndex < (int)pColumn->size(); nColumnIndex++) {
1573
1574                        if ( pColumn->get( nColumnIndex ) == pPattern ) {
1575                                bHasPattern = true;
1576                                break;
1577                        }
1578                }
1579
1580                if ( pRange->bInsert && !bHasPattern ) {       //fill
1581                        pColumn->add( pPattern);
1582                }
1583                else if ( !pRange->bInsert && bHasPattern ) {  // clear
1584                        pColumn->del( pPattern);
1585                }
1586        }
1587
1588                // remove all the empty patternlists at the end of the song
1589                for ( int i = pColumns->size() - 1; i != 0 ; i-- ) {
1590                        PatternList *pList = (*pColumns)[ i ];
1591                        int nSize = pList->size();
1592                        if ( nSize == 0 ) {
1593                                pColumns->erase( pColumns->begin() + i );
1594                                delete pList;
1595                        }
1596                        else {
1597                                break;
1598                        }
1599                }
1600        AudioEngine::get_instance()->unlock();
1601
1602
1603        // Update
1604        pSong->__is_modified = true;
1605        HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1606}
1607
1608
1609///drag & drop
1610void SongEditorPatternList::dragEnterEvent(QDragEnterEvent *event)
1611{
1612        if ( event->mimeData()->hasFormat("text/plain") ) {
1613                        event->acceptProposedAction();
1614        }
1615}
1616
1617
1618void SongEditorPatternList::dropEvent(QDropEvent *event)
1619{
1620        QString sText = event->mimeData()->text();
1621
1622        if( sText.startsWith("Songs:") || sText.startsWith("move instrument:") ){
1623                event->acceptProposedAction();
1624                return;
1625        }
1626
1627        if (sText.startsWith("move pattern:")) {
1628                Hydrogen *engine = Hydrogen::get_instance();
1629                int nSourcePattern = engine->getSelectedPatternNumber();
1630
1631                int nTargetPattern = event->pos().y() / m_nGridHeight;
1632
1633                if ( nSourcePattern == nTargetPattern ) {
1634                        event->acceptProposedAction();
1635                        return;
1636                }
1637
1638                SE_movePatternListItemAction *action = new SE_movePatternListItemAction( nSourcePattern , nTargetPattern ) ;
1639                HydrogenApp::get_instance()->m_undoStack->push( action );
1640                //movePatternLine( nSourcePattern , nTargetPattern );
1641
1642                event->acceptProposedAction();
1643        }else {
1644
1645                PatternList *pPatternList = Hydrogen::get_instance()->getSong()->get_pattern_list();
1646
1647                QStringList tokens = sText.split( "::" );
1648                QString sPatternName = tokens.at( 1 );
1649
1650                int nTargetPattern = event->pos().y() / m_nGridHeight;
1651
1652                //create a unique sequencefilename
1653                Song *song = Hydrogen::get_instance()->getSong();
1654                Pattern *pat = song->get_pattern_list()->get( nTargetPattern );
1655
1656                QString oldPatternName = pat->get_name();
1657
1658                time_t thetime;
1659                thetime = time(NULL);
1660                QString sequenceFileName = Preferences::get_instance()->getTmpDirectory() +QString("%1").arg(thetime)+ QString( "SEQ.xml" );
1661                SE_loadPatternAction *action = new SE_loadPatternAction(  sPatternName, oldPatternName, sequenceFileName, nTargetPattern );
1662                HydrogenApp::get_instance()->m_undoStack->push( action );
1663               
1664        }
1665}
1666
1667
1668
1669void SongEditorPatternList::movePatternLine( int nSourcePattern , int nTargetPattern )
1670{
1671                Hydrogen *engine = Hydrogen::get_instance();
1672
1673                Song *pSong = engine->getSong();
1674                PatternList *pPatternList = pSong->get_pattern_list();
1675
1676
1677
1678                // move instruments...
1679                H2Core::Pattern *pSourcePattern = pPatternList->get( nSourcePattern );//Instrument *pSourceInstr = pPatternList->get(nSourcePattern);
1680                if ( nSourcePattern < nTargetPattern) {
1681                        for (int nPatr = nSourcePattern; nPatr < nTargetPattern; nPatr++) {
1682                                H2Core::Pattern *pPattern = pPatternList->get(nPatr + 1);
1683                                pPatternList->replace( nPatr, pPattern );
1684                        }
1685                        pPatternList->replace( nTargetPattern, pSourcePattern );
1686                }
1687                else {
1688                        for (int nPatr = nSourcePattern; nPatr >= nTargetPattern; nPatr--) {
1689                                H2Core::Pattern *pPattern = pPatternList->get(nPatr - 1);
1690                                pPatternList->replace( nPatr, pPattern );
1691                        }
1692                        pPatternList->replace( nTargetPattern, pSourcePattern );
1693                }
1694                engine->setSelectedPatternNumber( nTargetPattern );
1695                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1696                pSong->__is_modified = true;
1697}
1698
1699
1700void SongEditorPatternList::mouseMoveEvent(QMouseEvent *event)
1701{
1702        if (!(event->buttons() & Qt::LeftButton)) {
1703                return;
1704        }
1705        if ( abs(event->pos().y() - __drag_start_position.y()) < (int)m_nGridHeight) {
1706                return;
1707        }
1708
1709
1710        QString sText = QString("move pattern:%1");
1711
1712        QDrag *pDrag = new QDrag(this);
1713        QMimeData *pMimeData = new QMimeData;
1714
1715        pMimeData->setText( sText );
1716        pDrag->setMimeData( pMimeData);
1717        //drag->setPixmap(iconPixmap);
1718
1719        pDrag->start( Qt::CopyAction | Qt::MoveAction );
1720
1721        QWidget::mouseMoveEvent(event);
1722}
1723
1724// ::::::::::::::::::::::::::
1725
1726const char* SongEditorPositionRuler::__class_name = "SongEditorPositionRuler";
1727
1728SongEditorPositionRuler::SongEditorPositionRuler( QWidget *parent )
1729 : QWidget( parent )
1730 , Object( __class_name )
1731 , m_bRightBtnPressed( false )
1732{
1733        setAttribute(Qt::WA_NoBackground);
1734
1735        m_nGridWidth = 16;
1736        Preferences *pref = Preferences::get_instance();
1737        m_nMaxPatternSequence = pref->getMaxBars();
1738
1739        m_nInitialWidth = m_nMaxPatternSequence * 16;
1740
1741        resize( m_nInitialWidth, m_nHeight );
1742        setFixedHeight( m_nHeight );
1743
1744        m_pBackgroundPixmap = new QPixmap( m_nInitialWidth, m_nHeight );        // initialize the pixmap
1745
1746        createBackground();     // create m_backgroundPixmap pixmap
1747
1748        // create tick position pixmap
1749        bool ok = m_tickPositionPixmap.load( Skin::getImagePath() + "/patternEditor/tickPosition.png" );
1750        if( ok == false ){
1751                ERRORLOG( "Error loading pixmap" );
1752        }
1753
1754        update();
1755
1756        m_pTimer = new QTimer(this);
1757        connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updatePosition()));
1758        m_pTimer->start(200);
1759}
1760
1761
1762
1763SongEditorPositionRuler::~SongEditorPositionRuler() {
1764        m_pTimer->stop();
1765}
1766
1767
1768uint SongEditorPositionRuler::getGridWidth()
1769{
1770        return m_nGridWidth;
1771}
1772
1773void SongEditorPositionRuler::setGridWidth( uint width )
1774{
1775        if ( SONG_EDITOR_MIN_GRID_WIDTH <= width && SONG_EDITOR_MAX_GRID_WIDTH >= width )
1776        {
1777                m_nGridWidth = width;
1778                createBackground ();
1779        }
1780}
1781
1782
1783void SongEditorPositionRuler::createBackground()
1784{
1785        UIStyle *pStyle = Preferences::get_instance()->getDefaultUIStyle();
1786        QColor backgroundColor( pStyle->m_songEditor_backgroundColor.getRed(), pStyle->m_songEditor_backgroundColor.getGreen(), pStyle->m_songEditor_backgroundColor.getBlue() );
1787        QColor textColor( pStyle->m_songEditor_textColor.getRed(), pStyle->m_songEditor_textColor.getGreen(), pStyle->m_songEditor_textColor.getBlue() );
1788        QColor textColorAlpha( pStyle->m_songEditor_textColor.getRed(), pStyle->m_songEditor_textColor.getGreen(), pStyle->m_songEditor_textColor.getBlue(), 45 );
1789        QColor alternateRowColor( pStyle->m_songEditor_alternateRowColor.getRed(), pStyle->m_songEditor_alternateRowColor.getGreen(), pStyle->m_songEditor_alternateRowColor.getBlue() );
1790
1791        m_pBackgroundPixmap->fill( backgroundColor );
1792
1793        Preferences *pref = Preferences::get_instance();
1794        QString family = pref->getApplicationFontFamily();
1795        int size = pref->getApplicationFontPointSize();
1796        QFont font( family, size );
1797
1798        QPainter p( m_pBackgroundPixmap );
1799        p.setFont( font );
1800
1801        p.fillRect( 0, 0, width(), 24, QColor( 67, 72, 83, 105) );
1802        char tmp[10];
1803        for (uint i = 0; i < m_nMaxPatternSequence + 1; i++) {
1804                uint x = 10 + i * m_nGridWidth;
1805                for ( int t = 0; t < static_cast<int>(Hydrogen::get_instance()->m_timelinetagvector.size()); t++){
1806                        if ( Hydrogen::get_instance()->m_timelinetagvector[t].m_htimelinetagbeat == i ) {
1807                                p.setPen( Qt::cyan );
1808                                p.drawText( x - m_nGridWidth / 2 , 12, m_nGridWidth * 2, height() , Qt::AlignCenter, "T");
1809                        }
1810                }
1811
1812                if ( (i % 4) == 0 ) {
1813                        p.setPen( textColor );
1814                        sprintf( tmp, "%d", i + 1 );
1815                        p.drawText( x - m_nGridWidth, 12, m_nGridWidth * 2, height(), Qt::AlignCenter, tmp );
1816
1817
1818                }
1819                else {
1820                        p.setPen( textColor );
1821                        p.drawLine( x, 32, x, 40 );
1822                }
1823
1824        }
1825
1826
1827//draw tempo content
1828        if(pref->__usetimeline){
1829                p.setPen( textColor );
1830        }else
1831        {
1832                p.setPen( textColorAlpha );
1833        }
1834        char tempo[10];
1835        for (uint i = 0; i < m_nMaxPatternSequence + 1; i++) {
1836                uint x = 10 + i * m_nGridWidth;
1837                p.drawLine( x, 2, x, 5 );
1838                p.drawLine( x, 19, x, 20 );
1839                for ( int t = 0; t < static_cast<int>(Hydrogen::get_instance()->m_timelinevector.size()); t++){
1840                        if ( Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebeat == i ) {
1841                                sprintf( tempo, "%d",  ((int)Hydrogen::get_instance()->m_timelinevector[t].m_htimelinebpm) );
1842                                p.drawText( x - m_nGridWidth, 3, m_nGridWidth * 2, height() / 2 - 5, Qt::AlignCenter, tempo );
1843                        }
1844                }
1845        }
1846
1847        p.setPen( QColor(35, 39, 51) );
1848        p.drawLine( 0, 0, width(), 0 );
1849
1850        p.fillRect ( 0, height() - 27, width(), 1, QColor(35, 39, 51) );
1851        p.fillRect ( 0, height() - 3, width(), 2, alternateRowColor );
1852
1853}
1854
1855
1856
1857void SongEditorPositionRuler::mouseMoveEvent(QMouseEvent *ev)
1858{
1859        if ( !m_bRightBtnPressed ) {
1860                // Click+drag triggers same action as clicking at new position
1861                mousePressEvent( ev );
1862        }
1863        else {
1864                // Right-click+drag
1865                int column = (ev->x() / m_nGridWidth);
1866                Preferences* pPref = Preferences::get_instance();
1867                if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) {
1868                        pPref->setPunchOutPos(-1);
1869                        return;
1870                }
1871                if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
1872                        return;
1873                }
1874                pPref->setPunchOutPos(column-1);
1875                update();
1876        }
1877}
1878
1879
1880
1881void SongEditorPositionRuler::mousePressEvent( QMouseEvent *ev )
1882{
1883
1884        if (ev->button() == Qt::LeftButton && ev->y() >= 26) {
1885                int column = (ev->x() / m_nGridWidth);
1886                m_bRightBtnPressed = false;
1887
1888                if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) {
1889                        return;
1890                }
1891       
1892                // disabling son relocates while in pattern mode as it causes weird behaviour. (jakob lund)
1893                if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
1894                        return;
1895                }
1896
1897                int nPatternPos = Hydrogen::get_instance()->getPatternPos();
1898                if ( nPatternPos != column ) {
1899                        Hydrogen::get_instance()->setPatternPos( column );
1900                        update();
1901                }
1902
1903                //time line test
1904                Hydrogen::get_instance()->setTimelineBpm();
1905
1906        }
1907        else if (ev->button() == Qt::MidButton && ev->y() >= 26) {
1908                int column = (ev->x() / m_nGridWidth);
1909                SongEditorPanelTagWidget dialog( this , column );
1910                if (dialog.exec() == QDialog::Accepted) {
1911                        //createBackground();
1912                }
1913        }
1914        else if (ev->button() == Qt::RightButton && ev->y() >= 26) {
1915                int column = (ev->x() / m_nGridWidth);
1916                Preferences* pPref = Preferences::get_instance();
1917                if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) {
1918                        pPref->unsetPunchArea();
1919                        return;
1920                }
1921                if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
1922                        return;
1923                }
1924                m_bRightBtnPressed = true;
1925                // Disable until mouse is moved
1926                pPref->setPunchInPos(column);
1927                pPref->setPunchOutPos(-1);
1928                update();
1929        }
1930        else if( ( ev->button() == Qt::LeftButton || ev->button() == Qt::RightButton ) && ev->y() <= 25 && Preferences::get_instance()->__usetimeline ){
1931                int column = (ev->x() / m_nGridWidth);
1932                SongEditorPanelBpmWidget dialog( this , column );
1933                if (dialog.exec() == QDialog::Accepted) {
1934                        //createBackground();
1935                }
1936        }
1937
1938}
1939
1940
1941
1942
1943void SongEditorPositionRuler::mouseReleaseEvent(QMouseEvent *ev)
1944{
1945        UNUSED( ev );
1946        m_bRightBtnPressed = false;
1947}
1948
1949
1950void SongEditorPositionRuler::paintEvent( QPaintEvent *ev )
1951{
1952        if (!isVisible()) {
1953                return;
1954        }
1955       
1956        Hydrogen *H = Hydrogen::get_instance();
1957
1958        float fPos = H->getPatternPos();
1959        int pIPos = Preferences::get_instance()->getPunchInPos();
1960        int pOPos = Preferences::get_instance()->getPunchOutPos();
1961
1962        if ( H->getCurrentPatternList()->size() != 0 ) {
1963                H2Core::Pattern *pPattern = H->getCurrentPatternList()->get( 0 );
1964
1965                if (pPattern != NULL){
1966                    fPos += (float)H->getTickPosition() / (float)pPattern->get_length();
1967                } else {
1968                    fPos += (float)H->getTickPosition() / (float)MAX_NOTES;
1969                }
1970        }
1971        else {
1972                // nessun pattern, uso la grandezza di default
1973                fPos += (float)H->getTickPosition() / (float)MAX_NOTES;
1974        }
1975
1976        if ( H->getSong()->get_mode() == Song::PATTERN_MODE ) {
1977                fPos = -1;
1978                pIPos = 0;
1979                pOPos = -1;
1980        }
1981
1982        QPainter painter(this);
1983        painter.drawPixmap( ev->rect(), *m_pBackgroundPixmap, ev->rect() );
1984
1985        if (fPos != -1) {
1986                uint x = (int)( 10 + fPos * m_nGridWidth - 11 / 2 );
1987                painter.drawPixmap( QRect( x, height() / 2, 11, 8), m_tickPositionPixmap, QRect(0, 0, 11, 8) );
1988                painter.setPen( QColor(35, 39, 51) );
1989                painter.drawLine( x + 5 , 8, x +5 , 24 );
1990        }
1991
1992        if ( pIPos <= pOPos ) {
1993                int xIn = (int)( 10 + pIPos * m_nGridWidth );
1994                int xOut = (int)( 9 + (pOPos+1) * m_nGridWidth );
1995                painter.fillRect( xIn, 30, xOut-xIn+1, 12, QColor(200, 100, 100, 100) );
1996                QPen pen(QColor(200, 100, 100));
1997                painter.setPen(pen);
1998                painter.drawRect( xIn, 30, xOut-xIn+1, 12 );
1999        }
2000
2001}
2002
2003
2004
2005void SongEditorPositionRuler::updatePosition()
2006{
2007        update();
2008}
2009
2010
2011void SongEditorPositionRuler::editTimeLineAction( int newPosition, float newBpm )
2012{
2013        Hydrogen* engine = Hydrogen::get_instance();
2014       
2015        //erase the value to set the new value
2016        if( engine->m_timelinevector.size() >= 1 ){
2017                for ( int t = 0; t < engine->m_timelinevector.size(); t++){
2018                        if ( engine->m_timelinevector[t].m_htimelinebeat == newPosition -1 ) {
2019                                engine->m_timelinevector.erase( engine->m_timelinevector.begin() +  t);
2020                        }
2021                }
2022        }
2023
2024        Hydrogen::HTimelineVector tlvector;
2025
2026        tlvector.m_htimelinebeat = newPosition -1 ;
2027
2028        if( newBpm < 30.0 ) newBpm = 30.0;
2029        if( newBpm > 500.0 ) newBpm = 500.0;   
2030        tlvector.m_htimelinebpm = newBpm;
2031        engine->m_timelinevector.push_back( tlvector );
2032        engine->sortTimelineVector();
2033        createBackground();
2034}
2035
2036
2037
2038void SongEditorPositionRuler::deleteTimeLinePosition( int position )
2039{
2040        Hydrogen* engine = Hydrogen::get_instance();
2041        //erase the value to set the new value
2042        if( engine->m_timelinevector.size() >= 1 ){
2043                for ( int t = 0; t < engine->m_timelinevector.size(); t++){
2044                        if ( engine->m_timelinevector[t].m_htimelinebeat == position -1 ) {
2045                                engine->m_timelinevector.erase( engine->m_timelinevector.begin() +  t);
2046                        }
2047                }
2048        }
2049        createBackground();
2050}
2051
2052
2053void SongEditorPositionRuler::editTagAction( QString text, int position, QString textToReplace)
2054{
2055        Hydrogen* engine = Hydrogen::get_instance();
2056
2057        //check vector for old entries and remove them.
2058        for( int i = 0; i < engine->m_timelinetagvector.size(); ++i ){
2059                if( ( engine->m_timelinetagvector[i].m_htimelinetag == textToReplace ) &&
2060                    ( engine->m_timelinetagvector[i].m_htimelinetagbeat == position ) ){
2061
2062                        engine->m_timelinetagvector.erase( engine->m_timelinetagvector.begin() + i );
2063                        break;
2064                }
2065        }
2066        Hydrogen::HTimelineTagVector tlvector;
2067        tlvector.m_htimelinetagbeat = position;
2068        tlvector.m_htimelinetag = text;
2069        engine->m_timelinetagvector.push_back( tlvector );
2070        engine->sortTimelineTagVector();
2071        createBackground();
2072}
2073
2074void SongEditorPositionRuler::deleteTagAction( QString text, int position )
2075{
2076
2077        Hydrogen* engine = Hydrogen::get_instance();
2078        for( int i = 0; i < engine->m_timelinetagvector.size(); ++i ){
2079                if( ( engine->m_timelinetagvector[i].m_htimelinetag == text ) &&
2080                    ( engine->m_timelinetagvector[i].m_htimelinetagbeat == position ) ){
2081
2082                        engine->m_timelinetagvector.erase( engine->m_timelinetagvector.begin() + i );
2083                        break;
2084                }
2085        }
2086        engine->sortTimelineTagVector();
2087        createBackground();
2088}
Note: See TracBrowser for help on using the browser.