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

Revision 270, 37.9 KB (checked in by wolke, 5 years ago)

improved pattern save for new directory structure

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 <QtGui>
24
25#include <assert.h>
26#include <algorithm>
27
28#include <hydrogen/Song.h>
29#include <hydrogen/hydrogen.h>
30#include <hydrogen/Preferences.h>
31#include <hydrogen/Pattern.h>
32#include <hydrogen/audio_engine.h>
33#include <hydrogen/event_queue.h>
34using namespace H2Core;
35
36
37#include "SongEditor.h"
38#include "SongEditorPanel.h"
39#include "../PatternEditor/PatternEditorPanel.h"
40#include "../HydrogenApp.h"
41#include "../widgets/Button.h"
42#include "../PatternFillDialog.h"
43#include "../PatternPropertiesDialog.h"
44#include "../SongPropertiesDialog.h"
45#include "../Skin.h"
46#include <hydrogen/LocalFileMng.h>
47
48
49SongEditor::SongEditor( QWidget *parent )
50 : QWidget( parent )
51 , Object( "SongEditor" )
52 , m_bSequenceChanged( true )
53 , m_bIsMoving( false )
54 , m_bShowLasso( false )
55{
56        setAttribute(Qt::WA_NoBackground);
57        setFocusPolicy (Qt::StrongFocus);
58
59        m_nGridWidth = 16;
60        m_nGridHeight = 18;
61
62        int m_nInitialWidth = 10 + m_nMaxPatternSequence * m_nGridWidth;
63        int m_nInitialHeight = 10;
64
65        this->resize( QSize(m_nInitialWidth, m_nInitialHeight) );
66
67        createBackground();     // create m_backgroundPixmap pixmap
68
69        update();
70}
71
72
73
74SongEditor::~SongEditor()
75{
76}
77
78
79
80int SongEditor::getGridWidth ()
81{
82        return m_nGridWidth;
83}
84
85
86
87void SongEditor::setGridWidth( uint width )
88{
89        if ( ( SONG_EDITOR_MIN_GRID_WIDTH <= width ) && ( SONG_EDITOR_MAX_GRID_WIDTH >= width ) ) {
90                m_nGridWidth = width;
91                this->resize ( 10 + m_nMaxPatternSequence * m_nGridWidth, height() );
92        }
93}
94
95
96
97void SongEditor::keyPressEvent ( QKeyEvent * ev )
98{
99        Hydrogen *pEngine = Hydrogen::get_instance();
100        PatternList *pPatternList = pEngine->getSong()->get_pattern_list();
101        vector<PatternList*>* pColumns = pEngine->getSong()->get_pattern_group_vector();
102
103        if ( ev->key() == Qt::Key_Delete ) {
104                if ( m_selectedCells.size() != 0 ) {
105                        AudioEngine::get_instance()->lock( "SongEditor::keyPressEvent" );
106                        // delete all selected cells
107                        for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
108                                QPoint cell = m_selectedCells[ i ];
109                                PatternList* pColumn = (*pColumns)[ cell.x() ];
110                                pColumn->del(pPatternList->get( cell.y() ) );
111                        }
112                        AudioEngine::get_instance()->unlock();
113
114                        m_selectedCells.clear();
115                        m_bSequenceChanged = true;
116                        update();
117                }
118                return;
119        }
120
121        ev->ignore();
122}
123
124
125
126void SongEditor::mousePressEvent( QMouseEvent *ev )
127{
128        if ( ev->x() < 10 ) {
129                return;
130        }
131        WARNINGLOG( "editor-pressed" );
132
133        int nRow = ev->y() / m_nGridHeight;
134        int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth;
135
136        if ( ev->modifiers() == Qt::ControlModifier ) {
137                INFOLOG( "[mousePressEvent] CTRL pressed!" );
138                m_bIsCtrlPressed = true;
139        }
140        else {
141                m_bIsCtrlPressed = false;
142        }
143
144        Hydrogen *pEngine = Hydrogen::get_instance();
145        Song *pSong = pEngine->getSong();
146        PatternList *pPatternList = pSong->get_pattern_list();
147
148        // don't lock the audio driver before checking that...
149        if ( nRow >= (int)pPatternList->get_size() || nRow < 0 || nColumn < 0 ) { return; }
150        AudioEngine::get_instance()->lock( "SongEditor::mousePressEvent" );
151
152
153        SongEditorActionMode actionMode = HydrogenApp::getInstance()->getSongEditorPanel()->getActionMode();
154        if ( actionMode == SELECT_ACTION ) {
155
156                bool bOverExistingPattern = false;
157                for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
158                        QPoint cell = m_selectedCells[ i ];
159                        if ( cell.x() == nColumn && cell.y() == nRow ) {
160                                bOverExistingPattern = true;
161                                break;
162                        }
163                }
164
165                if ( bOverExistingPattern ) {
166                        // MOVE PATTERNS
167//                      INFOLOG( "[mousePressEvent] Move patterns" );
168                        m_bIsMoving = true;
169                        m_bShowLasso = false;
170                        m_movingCells = m_selectedCells;
171
172                        m_clickPoint.setX( nColumn );
173                        m_clickPoint.setY( nRow );
174                }
175                else {
176//                      INFOLOG( "[mousePressEvent] Select patterns" );
177                        // select patterns
178                        m_bShowLasso = true;
179                        m_lasso.setCoords( ev->x(), ev->y(), ev->x(), ev->y() );
180                        setCursor( QCursor( Qt::CrossCursor ) );
181                        m_selectedCells.clear();
182                        m_selectedCells.push_back( QPoint( nColumn, nRow ) );
183                }
184        }
185        else if ( actionMode == DRAW_ACTION ) {
186                H2Core::Pattern *pPattern = pPatternList->get( nRow );
187                vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();     // E' la lista di "colonne" di pattern
188                if ( nColumn < (int)pColumns->size() ) {
189                        PatternList *pColumn = ( *pColumns )[ nColumn ];
190
191                        bool bFound = false;
192                        unsigned nColumnIndex = 0;
193                        for ( nColumnIndex = 0; nColumnIndex < pColumn->get_size(); nColumnIndex++) {
194                                if ( pColumn->get( nColumnIndex ) == pPattern ) { // il pattern e' gia presente
195                                        bFound = true;
196                                        break;
197                                }
198                        }
199
200                        if ( bFound ) {
201                                // DELETE PATTERN
202//                              INFOLOG( "[mousePressEvent] delete pattern" );
203                                pColumn->del( nColumnIndex );
204
205                                // elimino le colonne vuote
206                                for ( int i = pColumns->size() - 1; i >= 0; i-- ) {
207                                        PatternList *pColumn = ( *pColumns )[ i ];
208                                        if ( pColumn->get_size() == 0 ) {
209                                                pColumns->erase( pColumns->begin() + i );
210                                                delete pColumn;
211                                        }
212                                        else {
213                                                break;
214                                        }
215                                }
216                        }
217                        else {
218                                if ( nColumn < (int)pColumns->size() ) {
219                                        // ADD PATTERN
220//                                      INFOLOG( "[mousePressEvent] add pattern" );
221                                        m_selectedCells.clear();
222                                        pColumn->add( pPattern );
223                                }
224                        }
225                }
226                else {
227                        // ADD PATTERN (with spaces..)
228                        m_selectedCells.clear();
229                        int nSpaces = nColumn - pColumns->size();
230//                      INFOLOG( "[mousePressEvent] add pattern (with " + to_string( nSpaces ) + " spaces)" );
231
232                        PatternList *pColumn = new PatternList();
233                        pColumns->push_back( pColumn );
234
235                        for ( int i = 0; i < nSpaces; i++ ) {
236                                pColumn = new PatternList();
237                                pColumns->push_back( pColumn );
238                        }
239                        pColumn->add( pPattern );
240                }
241                pSong->__is_modified = true;
242        }
243
244        AudioEngine::get_instance()->unlock();
245
246        // update
247        m_bSequenceChanged = true;
248        update();
249}
250
251
252
253void SongEditor::mouseMoveEvent(QMouseEvent *ev)
254{
255        int nRow = ev->y() / m_nGridHeight;
256        int nColumn = ( (int)ev->x() - 10 ) / (int)m_nGridWidth;
257        PatternList *pPatternList = Hydrogen::get_instance()->getSong()->get_pattern_list();
258        vector<PatternList*>* pColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector();
259
260        if ( m_bIsMoving ) {
261//              WARNINGLOG( "[mouseMoveEvent] Move patterns not implemented yet" );
262
263                int nRowDiff = nRow  - m_clickPoint.y();
264                int nColumnDiff = nColumn - m_clickPoint.x();
265
266//              INFOLOG( "[mouseMoveEvent] row diff: "+ to_string( nRowDiff ) );
267//              INFOLOG( "[mouseMoveEvent] col diff: "+ to_string( nColumnDiff ) );
268
269                for ( int i = 0; i < (int)m_movingCells.size(); i++ ) {
270                        QPoint cell = m_movingCells[ i ];
271                        m_movingCells[ i ].setX( m_selectedCells[ i ].x() + nColumnDiff );
272                        m_movingCells[ i ].setY( m_selectedCells[ i ].y() + nRowDiff );
273                }
274
275                m_bSequenceChanged = true;
276                update();
277                return;
278        }
279
280        if ( m_bShowLasso ) {
281                // SELECTION
282                setCursor( QCursor( Qt::CrossCursor ) );
283                int x = ev->x();
284                int y = ev->y();
285                if ( x < 0 ) {
286                        x = 0;
287                }
288                if ( y < 0 ) {
289                        y = 0;
290                }
291                m_lasso.setBottomRight( QPoint( x, y ) );
292
293                // aggiorno la lista di celle selezionate
294                m_selectedCells.clear();
295
296                int nStartColumn = (int)( ( m_lasso.left() - 10.0 ) / m_nGridWidth );
297                int nEndColumn = nColumn;
298                if ( nStartColumn > nEndColumn ) {
299                        int nTemp = nEndColumn;
300                        nEndColumn = nStartColumn;
301                        nStartColumn = nTemp;
302                }
303
304                int nStartRow = m_lasso.top() / m_nGridHeight;
305                int nEndRow = nRow;
306                if ( nStartRow > nEndRow ) {
307                        int nTemp = nEndRow;
308                        nEndRow = nStartRow;
309                        nStartRow = nTemp;
310                }
311
312                for ( int nRow = nStartRow; nRow <= nEndRow; nRow++ ) {
313                        for ( int nCol = nStartColumn; nCol <= nEndColumn; nCol++ ) {
314                                if ( nRow >= (int)pPatternList->get_size() || nRow < 0 || nCol < 0 ) {
315                                        return;
316                                }
317                                H2Core::Pattern *pPattern = pPatternList->get( nRow );
318
319                                if ( nCol < (int)pColumns->size() ) {
320                                        PatternList *pColumn = ( *pColumns )[ nCol ];
321
322                                        for ( uint i = 0; i < pColumn->get_size(); i++) {
323                                                if ( pColumn->get(i) == pPattern ) { // esiste un pattern in questa posizione
324                                                        m_selectedCells.push_back( QPoint( nCol, nRow ) );
325                                                }
326                                        }
327                                }
328                        }
329                }
330
331                m_bSequenceChanged = true;
332                update();
333        }
334
335}
336
337
338
339void SongEditor::mouseReleaseEvent( QMouseEvent *ev )
340{
341        UNUSED( ev );
342//      INFOLOG( "[mouseReleaseEvent]" );
343
344        Hydrogen *pEngine = Hydrogen::get_instance();
345
346        PatternList *pPatternList = pEngine->getSong()->get_pattern_list();
347        vector<PatternList*>* pColumns = pEngine->getSong()->get_pattern_group_vector();
348
349        if ( m_bIsMoving ) {    // fine dello spostamento dei pattern
350                AudioEngine::get_instance()->lock( "SongEditor::mouseReleaseEvent" );
351                // create the new patterns
352                for ( uint i = 0; i < m_movingCells.size(); i++ ) {
353                        QPoint cell = m_movingCells[ i ];
354                        if ( cell.x() < 0 || cell.y() < 0 || cell.y() >= (int)pPatternList->get_size() ) {
355                                // skip
356                                continue;
357                        }
358                        // aggiungo un pattern per volta
359                        PatternList* pColumn = NULL;
360                        if ( cell.x() < (int)pColumns->size() ) {
361                                pColumn = (*pColumns)[ cell.x() ];
362                        }
363                        else {
364                                // creo dei patternlist vuoti
365                                int nSpaces = cell.x() - pColumns->size();
366                                for ( int i = 0; i <= nSpaces; i++ ) {
367                                        pColumn = new PatternList();
368                                        pColumns->push_back( pColumn );
369                                }
370                        }
371                        pColumn->add( pPatternList->get( cell.y() ) );
372                }
373
374                if ( m_bIsCtrlPressed ) {       // COPY
375                }
376                else {  // MOVE
377                        // remove the old patterns
378                        for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
379                                QPoint cell = m_selectedCells[ i ];
380                                PatternList* pColumn = NULL;
381                                if ( cell.x() < (int)pColumns->size() ) {
382                                        pColumn = (*pColumns)[ cell.x() ];
383                                }
384                                else {
385                                        pColumn = new PatternList();
386                                        pColumns->push_back( pColumn );
387                                }
388                                pColumn->del(pPatternList->get( cell.y() ) );
389                        }
390                }
391
392                // remove the empty patternlist at the end of the song
393                for ( int i = pColumns->size() - 1; i != 0 ; i-- ) {
394                        PatternList *pList = (*pColumns)[ i ];
395                        int nSize = pList->get_size();
396                        if ( nSize == 0 ) {
397                                pColumns->erase( pColumns->begin() + i );
398                                delete pList;
399                        }
400                        else {
401                                break;
402                        }
403                }
404
405
406                pEngine->getSong()->__is_modified = true;
407                AudioEngine::get_instance()->unlock();
408
409                m_bIsMoving = false;
410                m_movingCells.clear();
411                m_selectedCells.clear();
412        }
413
414        setCursor( QCursor( Qt::ArrowCursor ) );
415
416        m_bShowLasso = false;
417        m_bSequenceChanged = true;
418        m_bIsCtrlPressed = false;
419        update();
420}
421
422
423
424void SongEditor::paintEvent( QPaintEvent *ev )
425{
426/*      INFOLOG(
427                        "[paintEvent] x: " + to_string( ev->rect().x() ) +
428                        " y: " + to_string( ev->rect().y() ) +
429                        " w: " + to_string( ev->rect().width() ) +
430                        " h: " + to_string( ev->rect().height() )
431        );
432*/
433
434        // ridisegno tutto solo se sono cambiate le note
435        if (m_bSequenceChanged) {
436                m_bSequenceChanged = false;
437                drawSequence();
438        }
439
440        QPainter painter(this);
441        painter.drawPixmap( ev->rect(), *m_pSequencePixmap, ev->rect() );
442
443        if ( m_bShowLasso ) {
444                QPen pen( Qt::white );
445                pen.setStyle( Qt::DotLine );
446                painter.setPen( pen );
447                painter.drawRect( m_lasso );
448        }
449}
450
451
452
453void SongEditor::createBackground()
454{
455        UIStyle *pStyle = Preferences::getInstance()->getDefaultUIStyle();
456        QColor backgroundColor( pStyle->m_songEditor_backgroundColor.getRed(), pStyle->m_songEditor_backgroundColor.getGreen(), pStyle->m_songEditor_backgroundColor.getBlue() );
457        QColor alternateRowColor( pStyle->m_songEditor_alternateRowColor.getRed(), pStyle->m_songEditor_alternateRowColor.getGreen(), pStyle->m_songEditor_alternateRowColor.getBlue() );
458        QColor linesColor( pStyle->m_songEditor_lineColor.getRed(), pStyle->m_songEditor_lineColor.getGreen(), pStyle->m_songEditor_lineColor.getBlue() );
459
460        Hydrogen *pEngine = Hydrogen::get_instance();
461        Song *pSong = pEngine->getSong();
462
463        uint nPatterns = pSong->get_pattern_list()->get_size();
464
465        static int nOldHeight = -1;
466        int nNewHeight = m_nGridHeight * nPatterns;
467
468        if (nOldHeight != nNewHeight) {
469                // cambiamento di dimensioni...
470                if (nNewHeight == 0) {
471                        nNewHeight = 1; // the pixmap should not be empty
472                }
473
474                m_pBackgroundPixmap = new QPixmap( width(), nNewHeight );       // initialize the pixmap
475                m_pSequencePixmap = new QPixmap( width(), nNewHeight ); // initialize the pixmap
476                this->resize( QSize( width(), nNewHeight ) );
477        }
478
479        m_pBackgroundPixmap->fill( alternateRowColor );
480
481        QPainter p( m_pBackgroundPixmap );
482        p.setPen( linesColor );
483
484/*      // sfondo per celle scure (alternato)
485        for (uint i = 0; i < nPatterns; i++) {
486                if ( ( i % 2) != 0) {
487                        uint y = m_nGridHeight * i;
488                        p.fillRect ( 0, y, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
489                        p.fillRect ( 0, y + 2, m_nMaxPatternSequence * m_nGridWidth, m_nGridHeight - 4, alternateRowColor );
490                        p.fillRect ( 0, y + m_nGridHeight - 2, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
491                }
492        }
493*/
494        // celle...
495        p.setPen( linesColor );
496
497        // vertical lines
498        for (uint i = 0; i < m_nMaxPatternSequence + 1; i++) {
499                uint x = 10 + i * m_nGridWidth;
500                int x1 = x;
501                int x2 = x + m_nGridWidth;
502
503                p.drawLine( x1, 0, x1, m_nGridHeight * nPatterns );
504                p.drawLine( x2, 0, x2, m_nGridHeight * nPatterns );
505        }
506
507        p.setPen( linesColor );
508        // horizontal lines
509        for (uint i = 0; i < nPatterns; i++) {
510                uint y = m_nGridHeight * i;
511
512                int y1 = y + 2;
513                int y2 = y + m_nGridHeight - 2;
514
515                p.drawLine( 0, y1, (m_nMaxPatternSequence * m_nGridWidth), y1 );
516                p.drawLine( 0, y2, (m_nMaxPatternSequence * m_nGridWidth), y2 );
517        }
518
519
520        p.setPen( backgroundColor );
521        // horizontal lines (erase..)
522        for (uint i = 0; i < nPatterns + 1; i++) {
523                uint y = m_nGridHeight * i;
524
525                p.fillRect( 0, y, m_nMaxPatternSequence * m_nGridWidth, 2, backgroundColor );
526                p.drawLine( 0, y + m_nGridHeight - 1, m_nMaxPatternSequence * m_nGridWidth, y + m_nGridHeight - 1 );
527        }
528
529        //~ celle
530        m_bSequenceChanged = true;
531}
532
533void SongEditor::cleanUp(){
534
535        delete m_pBackgroundPixmap;
536        delete m_pSequencePixmap;
537}
538
539void SongEditor::drawSequence()
540{
541        QPainter p;
542        p.begin( m_pSequencePixmap );
543        p.drawPixmap( rect(), *m_pBackgroundPixmap, rect() );
544        p.end();
545
546        Song* song = Hydrogen::get_instance()->getSong();
547        PatternList *patList = song->get_pattern_list();
548        vector<PatternList*>* pColumns = song->get_pattern_group_vector();
549        uint listLength = patList->get_size();
550        for (uint i = 0; i < pColumns->size(); i++) {
551                PatternList* pColumn = (*pColumns)[ i ];
552
553                for (uint nPat = 0; nPat < pColumn->get_size(); ++nPat) {
554                        H2Core::Pattern *pat = pColumn->get( nPat );
555
556                        int position = -1;
557                        // find the position in pattern list
558                        for (uint j = 0; j < listLength; j++) {
559                                H2Core::Pattern *pat2 = patList->get( j );
560                                if (pat == pat2) {
561                                        position = j;
562                                        break;
563                                }
564                        }
565                        if (position == -1) {
566                                WARNINGLOG( "[drawSequence] position == -1, group = " + to_string( i ) );
567                        }
568                        drawPattern( i, position );
569                }
570        }
571
572        // Moving cells
573        p.begin( m_pSequencePixmap );
574//      p.setRasterOp( Qt::XorROP );
575
576// comix: this composition mode seems to be not available on Mac
577        p.setCompositionMode( QPainter::CompositionMode_Xor );
578        QPen pen( Qt::gray );
579        pen.setStyle( Qt::DotLine );
580        p.setPen( pen );
581        for ( uint i = 0; i < m_movingCells.size(); i++ ) {
582                int x = 10 + m_nGridWidth * ( m_movingCells[ i ] ).x();
583                int y = m_nGridHeight * ( m_movingCells[ i ] ).y();
584
585                QColor patternColor;
586                patternColor.setRgb( 255, 255, 255 );
587                p.fillRect( x + 2, y + 4, m_nGridWidth - 3, m_nGridHeight - 7, patternColor );
588        }
589
590}
591
592
593
594void SongEditor::drawPattern( int pos, int number )
595{
596        Preferences *pref = Preferences::getInstance();
597        UIStyle *pStyle = pref->getDefaultUIStyle();
598        QPainter p( m_pSequencePixmap );
599        QColor patternColor( pStyle->m_songEditor_pattern1Color.getRed(), pStyle->m_songEditor_pattern1Color.getGreen(), pStyle->m_songEditor_pattern1Color.getBlue() );
600
601        bool bIsSelected = false;
602        for ( uint i = 0; i < m_selectedCells.size(); i++ ) {
603                QPoint point = m_selectedCells[ i ];
604                if ( point.x() == pos && point.y() == number ) {
605                        bIsSelected = true;
606                        break;
607                }
608        }
609
610        if ( bIsSelected ) {
611                patternColor = patternColor.dark( 130 );
612        }
613
614        int x = 10 + m_nGridWidth * pos;
615        int y = m_nGridHeight * number;
616
617//      p.setPen( patternColor.light( 120 ) );  // willie - For the bevel - haven't yet figured how it's supposed to work...
618        p.fillRect( x + 1, y + 3, m_nGridWidth - 1, m_nGridHeight - 5, patternColor );
619}
620
621
622
623
624
625// :::::::::::::::::::
626
627
628
629
630
631SongEditorPatternList::SongEditorPatternList( QWidget *parent )
632 : QWidget( parent )
633 , Object( "SongEditorPatternList" )
634 , EventListener()
635 , m_pBackgroundPixmap( NULL )
636{
637        m_nWidth = 200;
638        m_nGridHeight = 18;
639        setAttribute(Qt::WA_NoBackground);
640       
641        patternBeingEdited = NULL;
642       
643        line = new QLineEdit( "Inline Pattern Name", this );
644        line->setFrame( false );
645        line->hide();
646        connect( line, SIGNAL(editingFinished()), this, SLOT(inlineEditingFinished()) );
647        connect( line, SIGNAL(returnPressed()), this, SLOT(inlineEditingEntered()) );
648
649        this->resize( m_nWidth, m_nInitialHeight );
650
651        m_labelBackgroundLight.load( Skin::getImagePath() + "/songEditor/songEditorLabelBG.png" );
652        m_labelBackgroundDark.load( Skin::getImagePath() + "/songEditor/songEditorLabelABG.png" );
653        m_labelBackgroundSelected.load( Skin::getImagePath() + "/songEditor/songEditorLabelSBG.png" );
654        m_playingPattern_on_Pixmap.load( Skin::getImagePath() + "/songEditor/playingPattern_on.png" );
655        m_playingPattern_off_Pixmap.load( Skin::getImagePath() + "/songEditor/playingPattern_off.png" );
656
657        m_pPatternPopup = new QMenu( this );
658        m_pPatternPopup->addAction( trUtf8("Edit"),  this, SLOT( patternPopup_edit() ) );
659        m_pPatternPopup->addAction( trUtf8("Copy"),  this, SLOT( patternPopup_copy() ) );
660        m_pPatternPopup->addAction( trUtf8("Delete"),  this, SLOT( patternPopup_delete() ) );
661        m_pPatternPopup->addAction( trUtf8("Fill/Clear ..."),  this, SLOT( patternPopup_fill() ) );
662        m_pPatternPopup->addAction( trUtf8("Properties"),  this, SLOT( patternPopup_properties() ) );
663        m_pPatternPopup->addAction( trUtf8("Load Pattern"),  this, SLOT( patternPopup_load() ) );
664        m_pPatternPopup->addAction( trUtf8("Save Pattern"),  this, SLOT( patternPopup_save() ) );
665
666        HydrogenApp::getInstance()->addEventListener( this );
667
668        createBackground();
669        update();
670}
671
672
673
674SongEditorPatternList::~SongEditorPatternList()
675{
676}
677
678
679void SongEditorPatternList::patternChangedEvent() {
680        createBackground();
681        update();
682}
683
684
685/// Single click, select the next pattern
686void SongEditorPatternList::mousePressEvent( QMouseEvent *ev )
687{
688        int row = (ev->y() / m_nGridHeight);
689
690        Hydrogen *engine = Hydrogen::get_instance();
691        Song *song = engine->getSong();
692        PatternList *patternList = song->get_pattern_list();
693
694        if ( row >= (int)patternList->get_size() ) {
695                return;
696        }
697
698        if ( ev->button() == Qt::MidButton || ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::RightButton || ev->modifiers() == Qt::ControlModifier && ev->button() == Qt::LeftButton ){
699                togglePattern( row );
700        } else {
701                engine->setSelectedPatternNumber( row );
702                if (ev->button() == Qt::RightButton)  {
703        /*
704                        if ( song->getMode() == Song::PATTERN_MODE ) {
705       
706                                PatternList *pCurrentPatternList = engine->getCurrentPatternList();
707                                if ( pCurrentPatternList->get_size() == 0 ) {
708                                        // nessun pattern e' attivo. seleziono subito questo.
709                                        pCurrentPatternList->add( patternList->get( row ) );
710                                }
711                                else {
712                                        engine->setNextPattern( row );
713                                }
714                        }
715        */
716                        m_pPatternPopup->popup( QPoint( ev->globalX(), ev->globalY() ) );
717                }
718        }
719
720        createBackground();
721        update();
722}
723
724
725///
726/// Start/stop playing a pattern in "pattern mode"
727///
728void SongEditorPatternList::togglePattern( int row ) {
729
730        Hydrogen *engine = Hydrogen::get_instance();
731/*      Song *song = engine->getSong();
732        PatternList *patternList = song->get_pattern_list();*/
733
734//      PatternList *pCurrentPatternList = engine->getCurrentPatternList();
735
736//      bool isPatternPlaying = false;
737        engine->sequencer_setNextPattern( row, false, true );
738
739//      for ( uint i = 0; i < pCurrentPatternList->get_size(); ++i ) {
740//              if ( pCurrentPatternList->get( i ) == patternList->get( row ) ) {
741//                      // the pattern is already playing, stop it!
742//                      isPatternPlaying = true;
743//                      break;
744//              }
745//      }
746//
747//      if ( isPatternPlaying ) {
748//              //pCurrentPatternList->del( patternList->get( row ) );
749//              engine->sequencer_setNextPattern( row, false, true );   // remove from the playing pattern list
750//      }
751//      else {
752//              // the pattern is not playing, add it to the list
753//              //pCurrentPatternList->add( patternList->get( row ) );
754//              engine->sequencer_setNextPattern( row, true, false );   // add to the playing pattern list
755//      }
756
757        createBackground();
758        update();
759}
760
761
762void SongEditorPatternList::mouseDoubleClickEvent( QMouseEvent *ev )
763{
764        int row = (ev->y() / m_nGridHeight);
765        inlineEditPatternName( row );
766}
767
768void SongEditorPatternList::inlineEditPatternName( int row )
769{
770        Hydrogen *engine = Hydrogen::get_instance();
771        Song *song = engine->getSong();
772        PatternList *patternList = song->get_pattern_list();
773
774        if ( row >= (int)patternList->get_size() ) {
775                return;
776        }
777        patternBeingEdited = patternList->get( row );
778        line->setGeometry( 23, row * m_nGridHeight , m_nWidth - 23, m_nGridHeight  );
779        line->setText( patternBeingEdited->get_name() );
780        line->selectAll();
781        line->show();
782        line->setFocus();
783}
784
785void SongEditorPatternList::inlineEditingEntered()
786{
787        assert( patternBeingEdited != NULL );
788        if ( PatternPropertiesDialog::nameCheck( line->text() ) )
789        {
790                patternBeingEdited->set_name( line->text() );
791                Hydrogen::get_instance()->getSong()->__is_modified = true;
792                EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
793                createBackground();
794                update();
795        }
796//      patternBeingEdited = NULL;
797}
798
799
800void SongEditorPatternList::inlineEditingFinished()
801{
802        patternBeingEdited = NULL;
803        line->hide();
804}
805
806
807void SongEditorPatternList::paintEvent( QPaintEvent *ev )
808{
809        QPainter painter(this);
810        painter.drawPixmap( ev->rect(), *m_pBackgroundPixmap, ev->rect() );
811}
812
813
814
815void SongEditorPatternList::updateEditor()
816{
817        if(!isVisible()) {
818                return;
819        }
820
821        update();
822}
823
824
825
826void SongEditorPatternList::createBackground()
827{
828        Preferences *pref = Preferences::getInstance();
829        UIStyle *pStyle = pref->getDefaultUIStyle();
830        QColor textColor( pStyle->m_songEditor_textColor.getRed(), pStyle->m_songEditor_textColor.getGreen(), pStyle->m_songEditor_textColor.getBlue() );
831
832        QString family = pref->getApplicationFontFamily();
833        int size = pref->getApplicationFontPointSize();
834        QFont textFont( family, size );
835
836        QFont boldTextFont( textFont);
837        boldTextFont.setPointSize(10);
838        boldTextFont.setBold( true );
839
840        Hydrogen *pEngine = Hydrogen::get_instance();
841        Song *pSong = pEngine->getSong();
842        int nPatterns = pSong->get_pattern_list()->get_size();
843        int nSelectedPattern = pEngine->getSelectedPatternNumber();
844
845        static int oldHeight = -1;
846        int newHeight = m_nGridHeight * nPatterns;
847
848        if (oldHeight != newHeight) {
849                if (newHeight == 0) {
850                        newHeight = 1;  // the pixmap should not be empty
851                }
852                delete m_pBackgroundPixmap;
853                m_pBackgroundPixmap = new QPixmap( m_nWidth, newHeight );       // initialize the pixmap
854                this->resize( m_nWidth, newHeight );
855        }
856        m_pBackgroundPixmap->fill( Qt::black );
857
858        QPainter p( m_pBackgroundPixmap );
859        p.setFont( boldTextFont );
860
861        for ( int i = 0; i < nPatterns; i++ ) {
862                uint y = m_nGridHeight * i;
863                if ( i == nSelectedPattern ) {
864                        p.drawPixmap( QPoint( 0, y ), m_labelBackgroundSelected );
865                }
866                else {
867                        if ( ( i % 2) == 0 ) {
868                                p.drawPixmap( QPoint( 0, y ), m_labelBackgroundDark );
869                        }
870                        else {
871                                p.drawPixmap( QPoint( 0, y ), m_labelBackgroundLight );
872                        }
873                }
874        }
875
876        PatternList *pCurrentPatternList = pEngine->getCurrentPatternList();
877
878        /// paint the foreground (pattern name etc.)
879        for ( int i = 0; i < nPatterns; i++ ) {
880                H2Core::Pattern *pPattern = pSong->get_pattern_list()->get(i);
881                //uint y = m_nGridHeight * i;
882
883                // Text
884                bool bNext = false, bActive = false;
885/*              for (uint j = 0; j < pCurrentPatternList->get_size(); j++) {
886                        if ( pPattern == pCurrentPatternList->get(j) ) {
887                                bActive = true;
888                                break;
889                        }
890                }*/
891                if ( pCurrentPatternList->index_of( pPattern ) != -1 ) bActive = true;
892                if ( pEngine->getNextPatterns()->index_of( pPattern ) != -1 ) bNext = true;
893
894                if ( i == nSelectedPattern ) {
895                        p.setPen( QColor( 0,0,0 ) );
896                }
897                else {
898                        p.setPen( textColor );
899                }
900
901                uint text_y = i * m_nGridHeight;
902                if ( bNext ) {
903                        p.drawPixmap( QPoint( 5, text_y + 3 ), m_playingPattern_off_Pixmap );
904                }
905                else if (bActive) {
906//                      p.drawText( 5, text_y - 1 - m_nGridHeight, m_nWidth - 25, m_nGridHeight + 2, Qt::AlignVCenter, ">" );
907               
908                        //mark active pattern with triangular
909                        if( ! pref->patternModePlaysSelected() ){
910                                p.drawPixmap( QPoint( 5, text_y + 3 ), m_playingPattern_on_Pixmap );
911                        }
912                }
913
914
915                p.drawText( 25, text_y - 1, m_nWidth - 25, m_nGridHeight + 2, Qt::AlignVCenter, pPattern->get_name() );
916        }
917
918}
919
920
921
922void SongEditorPatternList::patternPopup_load()
923{
924
925        Hydrogen *engine = Hydrogen::get_instance();
926        int tmpselectedpatternpos = engine->getSelectedPatternNumber();
927        Song *song = engine->getSong();
928        PatternList *pPatternList = song->get_pattern_list();
929        Instrument *instr = song->get_instrument_list()->get( 0 );
930        assert( instr );
931       
932        QString sDrumkitDir = Preferences::getInstance()->getDataDirectory() + "drumkits/" + instr->get_drumkit_name();
933       
934        QDir dirPattern( sDrumkitDir + "/Pattern" );
935        QFileDialog *fd = new QFileDialog(this);
936        fd->setFileMode(QFileDialog::ExistingFile);
937        fd->setFilter( trUtf8("Hydrogen Song (*.h2pattern)") );
938        fd->setDirectory(dirPattern );
939
940        fd->setWindowTitle( trUtf8( "Open Pattern" ) );
941
942        QString filename = "";
943        if (fd->exec() == QDialog::Accepted) {
944                filename = fd->selectedFiles().first();
945        }
946        else
947        {
948                return;
949        }
950
951        LocalFileMng mng;
952        LocalFileMng fileMng;
953        Pattern* err = fileMng.loadPattern( filename );
954        if ( err == 0 ) {
955                _ERRORLOG( "Error loading the pattern" );
956        }else{
957                H2Core::Pattern *pNewPattern = err;
958                pPatternList->add( pNewPattern );
959                song->__is_modified = true;
960                createBackground();
961                update();
962        }
963
964        int listsize = pPatternList->get_size();
965        engine->setSelectedPatternNumber( listsize -1 );
966        Pattern *pTemp = pPatternList->get( engine->getSelectedPatternNumber() );
967        pPatternList->replace( pPatternList->get( tmpselectedpatternpos ), listsize -1);
968        pPatternList->replace( pTemp, tmpselectedpatternpos );
969        listsize = pPatternList->get_size();
970        engine->setSelectedPatternNumber( listsize -1 );
971        patternPopup_delete();
972        engine->setSelectedPatternNumber( tmpselectedpatternpos );
973        HydrogenApp::getInstance()->getSongEditorPanel()->updateAll();
974
975}
976
977
978
979void SongEditorPatternList::patternPopup_save()
980{       
981        Hydrogen *engine = Hydrogen::get_instance();
982        int nSelectedPattern = engine->getSelectedPatternNumber();
983        Song *song = engine->getSong();
984        Pattern *pat = song->get_pattern_list()->get( nSelectedPattern );
985
986        QString patternname = pat->get_name();
987        QString realpatternname = patternname;
988
989        LocalFileMng fileMng;
990        int err = fileMng.savePattern( song , nSelectedPattern, patternname, realpatternname, 1 );
991        if ( err != 0 ) {
992                _ERRORLOG( "Error saving the pattern" );
993        }
994}
995
996void SongEditorPatternList::patternPopup_edit()
997{
998        HydrogenApp::getInstance()->getPatternEditorPanel()->show();
999        HydrogenApp::getInstance()->getPatternEditorPanel()->setFocus();
1000}
1001
1002
1003
1004void SongEditorPatternList::patternPopup_properties()
1005{
1006        Hydrogen *engine = Hydrogen::get_instance();
1007        Song *song = engine->getSong();
1008        PatternList *patternList = song->get_pattern_list();
1009
1010        int nSelectedPattern = engine->getSelectedPatternNumber();
1011        H2Core::Pattern *pattern = patternList->get( nSelectedPattern );
1012
1013        PatternPropertiesDialog *dialog = new PatternPropertiesDialog(this, pattern);
1014        if (dialog->exec() == QDialog::Accepted) {
1015//              Hydrogen *engine = Hydrogen::get_instance();
1016//              Song *song = engine->getSong();
1017                song->__is_modified = true;
1018                EventQueue::get_instance()->push_event( EVENT_SELECTED_PATTERN_CHANGED, -1 );
1019                createBackground();
1020                update();
1021        }
1022        delete dialog;
1023        dialog = NULL;
1024}
1025
1026
1027
1028void SongEditorPatternList::patternPopup_delete()
1029{
1030        Hydrogen *pEngine = Hydrogen::get_instance();
1031
1032//      int state = engine->getState();
1033//      // per ora non lascio possibile la cancellazione del pattern durante l'esecuzione
1034//      // da togliere quando correggo il bug
1035//         if (state == PLAYING) {
1036//                 QMessageBox::information( this, "Hydrogen", trUtf8("Can't delete the pattern while the audio engine is playing"));
1037//                 return;
1038//         }
1039
1040        if ( pEngine->getSong()->get_mode() == Song::PATTERN_MODE ) {
1041                pEngine->sequencer_setNextPattern( -1, false, false );  // reimposto il prossimo pattern a NULL, altrimenti viene scelto quello che sto distruggendo ora...
1042        }
1043
1044//      pEngine->sequencer_stop();
1045
1046// "lock engine" I am not sure, but think this is unnecessarily. -wolke-
1047//      AudioEngine::get_instance()->lock( "SongEditorPatternList::patternPopup_delete" );
1048
1049        Song *song = pEngine->getSong();
1050        PatternList *pSongPatternList = song->get_pattern_list();
1051
1052        H2Core::Pattern *pattern = pSongPatternList->get( pEngine->getSelectedPatternNumber() );
1053        INFOLOG( "[patternPopup_delete] Delete pattern: " + pattern->get_name() + " @" + to_string( (long)pattern ) );
1054        pSongPatternList->del(pattern);
1055
1056        vector<PatternList*> *patternGroupVect = song->get_pattern_group_vector();
1057
1058        uint i = 0;
1059        while (i < patternGroupVect->size() ) {
1060                PatternList *list = (*patternGroupVect)[i];
1061
1062                uint j = 0;
1063                while ( j < list->get_size() ) {
1064                        H2Core::Pattern *pOldPattern = list->get( j );
1065                        if (pOldPattern == pattern ) {
1066                                list->del( j );
1067                                continue;
1068                        }
1069                        j++;
1070                }
1071//              for (uint j = 0; j < list->get_size(); j++) {
1072//                      Pattern *pOldPattern = list->get( j );
1073//                      if (pOldPattern == pattern ) {
1074//                              list->del( j );
1075//                      }
1076//              }
1077
1078/*              if (list->get_size() == 0 ) {
1079                        patternGroupVect->erase( patternGroupVect->begin() + i );
1080                        delete list;
1081                        list = NULL;
1082                }
1083                else {
1084*/                      i++;
1085//              }
1086        }
1087
1088
1089        PatternList *list = pEngine->getCurrentPatternList();
1090        list->del( pattern );
1091        // se esiste, seleziono il primo pattern
1092        if ( pSongPatternList->get_size() > 0 ) {
1093                H2Core::Pattern *pFirstPattern = pSongPatternList->get( 0 );
1094                list->add( pFirstPattern );
1095                // Cambio due volte...cosi' il pattern editor viene costretto ad aggiornarsi
1096                pEngine->setSelectedPatternNumber( -1 );
1097                pEngine->setSelectedPatternNumber( 0 );
1098        }
1099        else {
1100                // there's no patterns..
1101                pEngine->setSelectedPatternNumber( -1 );        // cosi' il pattern editor viene costretto ad aggiornarsi
1102        }
1103
1104        delete pattern;
1105
1106        song->__is_modified = true;
1107
1108// "unlock" I am not sure, but think this is unnecessarily. -wolke-
1109//      AudioEngine::get_instance()->unlock();
1110
1111        ( HydrogenApp::getInstance() )->getSongEditorPanel()->updateAll();
1112}
1113
1114
1115
1116void SongEditorPatternList::patternPopup_copy()
1117{
1118        Hydrogen *pEngine = Hydrogen::get_instance();
1119        Song *pSong = pEngine->getSong();
1120        PatternList *pPatternList = pSong->get_pattern_list();
1121        int nSelectedPattern = pEngine->getSelectedPatternNumber();
1122        H2Core::Pattern *pPattern = pPatternList->get( nSelectedPattern );
1123
1124        H2Core::Pattern *pNewPattern = pPattern->copy();
1125        pPatternList->add( pNewPattern );
1126
1127        // rename the copied pattern
1128        PatternPropertiesDialog *dialog = new PatternPropertiesDialog( this, pNewPattern );
1129        if ( dialog->exec() == QDialog::Accepted ) {
1130                pSong->__is_modified = true;
1131                pEngine->setSelectedPatternNumber(pPatternList->get_size() - 1);        // select the last pattern (the copied one)
1132                if (pSong->get_mode() == Song::PATTERN_MODE) {
1133                        pEngine->sequencer_setNextPattern( pPatternList->get_size() - 1, false, false );        // select the last pattern (the new copied pattern)
1134                }
1135        }
1136        else {
1137                pPatternList->del( pNewPattern );
1138                delete pNewPattern;
1139        }
1140        delete dialog;
1141
1142        HydrogenApp::getInstance()->getSongEditorPanel()->updateAll();
1143}
1144
1145void SongEditorPatternList::patternPopup_fill()
1146{
1147        Hydrogen *pEngine = Hydrogen::get_instance();
1148        int nSelectedPattern = pEngine->getSelectedPatternNumber();
1149        FillRange range;
1150        PatternFillDialog *dialog = new PatternFillDialog( this, &range );
1151        SongEditorPanel *pSEPanel = HydrogenApp::getInstance()->getSongEditorPanel();
1152
1153
1154        // use a PatternFillDialog to get the range and mode data
1155        if ( dialog->exec() == QDialog::Accepted ) {
1156                fillRangeWithPattern(&range, nSelectedPattern);
1157                pSEPanel->updateAll();
1158        }
1159
1160        delete dialog;
1161
1162}
1163
1164
1165void SongEditorPatternList::fillRangeWithPattern(FillRange* pRange, int nPattern)
1166{
1167        Hydrogen *pEngine = Hydrogen::get_instance();
1168        AudioEngine::get_instance()->lock( "SongEditorPatternList::fillRangeWithPattern" );
1169
1170
1171        Song *pSong = pEngine->getSong();
1172        PatternList *pPatternList = pSong->get_pattern_list();
1173        H2Core::Pattern *pPattern = pPatternList->get( nPattern );
1174        vector<PatternList*> *pColumns = pSong->get_pattern_group_vector();     // E' la lista di "colonne" di pattern
1175        PatternList *pColumn;
1176
1177        int nColumn, nColumnIndex;
1178        bool bHasPattern = false;
1179        int fromVal = pRange->fromVal - 1;
1180        int toVal   = pRange->toVal;
1181
1182
1183
1184        // Add patternlists to PatternGroupVector as necessary
1185
1186        int nDelta = toVal - pColumns->size() + 1;
1187
1188        for ( int i = 0; i < nDelta; i++ ) {
1189                pColumn = new PatternList();
1190                pColumns->push_back( pColumn );
1191        }
1192
1193
1194        // Fill or Clear each cell in range
1195
1196        for ( nColumn = fromVal; nColumn < toVal; nColumn++ ) {
1197
1198                // expand Pattern
1199                pColumn = ( *pColumns )[ nColumn ];
1200
1201                bHasPattern = false;
1202
1203                // check whether the pattern (and column) already exists
1204                for ( nColumnIndex = 0; pColumn && nColumnIndex < (int)pColumn->get_size(); nColumnIndex++) {
1205
1206                        if ( pColumn->get( nColumnIndex ) == pPattern ) {
1207                                bHasPattern = true;
1208                                break;
1209                        }
1210                }
1211
1212                if ( pRange->bInsert && !bHasPattern ) {       //fill
1213                        pColumn->add( pPattern);
1214                }
1215                else if ( !pRange->bInsert && bHasPattern ) {  // clear
1216                        pColumn->del( pPattern);
1217                }
1218        }
1219
1220                // remove all the empty patternlists at the end of the song
1221                for ( int i = pColumns->size() - 1; i != 0 ; i-- ) {
1222                        PatternList *pList = (*pColumns)[ i ];
1223                        int nSize = pList->get_size();
1224                        if ( nSize == 0 ) {
1225                                pColumns->erase( pColumns->begin() + i );
1226                                delete pList;
1227                        }
1228                        else {
1229                                break;
1230                        }
1231                }
1232        AudioEngine::get_instance()->unlock();
1233
1234
1235        // Update
1236        pSong->__is_modified = true;
1237}
1238
1239
1240// ::::::::::::::::::::::::::
1241
1242
1243
1244SongEditorPositionRuler::SongEditorPositionRuler( QWidget *parent )
1245 : QWidget( parent )
1246 , Object( "SongEditorPositionRuler" )
1247{
1248        setAttribute(Qt::WA_NoBackground);
1249
1250        m_nGridWidth = 16;
1251
1252        resize( m_nInitialWidth, m_nHeight );
1253        setFixedHeight( m_nHeight );
1254
1255        m_pBackgroundPixmap = new QPixmap( m_nInitialWidth, m_nHeight );        // initialize the pixmap
1256
1257        createBackground();     // create m_backgroundPixmap pixmap
1258
1259        // create tick position pixmap
1260        bool ok = m_tickPositionPixmap.load( Skin::getImagePath() + "/patternEditor/tickPosition.png" );
1261        if( ok == false ){
1262                ERRORLOG( "Error loading pixmap" );
1263        }
1264
1265        update();
1266
1267        m_pTimer = new QTimer(this);
1268        connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updatePosition()));
1269        m_pTimer->start(200);
1270}
1271
1272
1273
1274SongEditorPositionRuler::~SongEditorPositionRuler() {
1275        m_pTimer->stop();
1276}
1277
1278
1279uint SongEditorPositionRuler::getGridWidth()
1280{
1281        return m_nGridWidth;
1282}
1283
1284void SongEditorPositionRuler::setGridWidth( uint width )
1285{
1286        if ( SONG_EDITOR_MIN_GRID_WIDTH <= width && SONG_EDITOR_MAX_GRID_WIDTH >= width )
1287        {
1288                m_nGridWidth = width;
1289                createBackground ();
1290        }
1291}
1292
1293
1294void SongEditorPositionRuler::createBackground()
1295{
1296        UIStyle *pStyle = Preferences::getInstance()->getDefaultUIStyle();
1297        QColor backgroundColor( pStyle->m_songEditor_backgroundColor.getRed(), pStyle->m_songEditor_backgroundColor.getGreen(), pStyle->m_songEditor_backgroundColor.getBlue() );
1298        QColor textColor( pStyle->m_songEditor_textColor.getRed(), pStyle->m_songEditor_textColor.getGreen(), pStyle->m_songEditor_textColor.getBlue() );
1299        QColor alternateRowColor( pStyle->m_songEditor_alternateRowColor.getRed(), pStyle->m_songEditor_alternateRowColor.getGreen(), pStyle->m_songEditor_alternateRowColor.getBlue() );
1300
1301        m_pBackgroundPixmap->fill( backgroundColor );
1302
1303        Preferences *pref = Preferences::getInstance();
1304        QString family = pref->getApplicationFontFamily();
1305        int size = pref->getApplicationFontPointSize();
1306        QFont font( family, size );
1307
1308        QPainter p( m_pBackgroundPixmap );
1309        p.setFont( font );
1310
1311        char tmp[10];
1312        for (uint i = 0; i < m_nMaxPatternSequence + 1; i++) {
1313                uint x = 10 + i * m_nGridWidth;
1314                if ( (i % 4) == 0 ) {
1315                        p.setPen( textColor );
1316                        sprintf( tmp, "%d", i + 1 );
1317                        p.drawText( x - m_nGridWidth, 0, m_nGridWidth * 2, height(), Qt::AlignCenter, tmp );
1318                }
1319                else {
1320                        p.setPen( textColor );
1321                        p.drawLine( x, 10, x, m_nHeight - 10 );
1322                }
1323        }
1324
1325        p.setPen( QColor(35, 39, 51) );
1326        p.drawLine( 0, 0, width(), 0 );
1327
1328        p.fillRect ( 0, height() - 3, width(), 2, alternateRowColor );
1329
1330}
1331
1332
1333
1334void SongEditorPositionRuler::mouseMoveEvent(QMouseEvent *ev)
1335{
1336        mousePressEvent( ev );
1337}
1338
1339
1340
1341void SongEditorPositionRuler::mousePressEvent( QMouseEvent *ev )
1342{
1343        int column = (ev->x() / m_nGridWidth);
1344
1345        if ( column >= (int)Hydrogen::get_instance()->getSong()->get_pattern_group_vector()->size() ) {
1346                return;
1347        }
1348       
1349        // disabling son relocates while in pattern mode as it causes weird behaviour. (jakob lund)
1350        if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
1351                return;
1352        }
1353
1354        int nPatternPos = Hydrogen::get_instance()->getPatternPos();
1355        if ( nPatternPos != column ) {
1356                Hydrogen::get_instance()->setPatternPos( column );
1357                update();
1358        }
1359}
1360
1361
1362
1363void SongEditorPositionRuler::paintEvent( QPaintEvent *ev )
1364{
1365        if (!isVisible()) {
1366                return;
1367        }
1368
1369        static float fOldPosition = -1000;
1370        float fPos = Hydrogen::get_instance()->getPatternPos();
1371
1372        if ( Hydrogen::get_instance()->getCurrentPatternList()->get_size() != 0 ) {
1373                H2Core::Pattern *pPattern = Hydrogen::get_instance()->getCurrentPatternList()->get( 0 );
1374                fPos += (float)Hydrogen::get_instance()->getTickPosition() / (float)pPattern->get_lenght();
1375        }
1376        else {
1377                // nessun pattern, uso la grandezza di default
1378                fPos += (float)Hydrogen::get_instance()->getTickPosition() / (float)MAX_NOTES;
1379        }
1380
1381        if ( fOldPosition != fPos ) {
1382                fOldPosition = fPos;
1383        }
1384
1385        if ( Hydrogen::get_instance()->getSong()->get_mode() == Song::PATTERN_MODE ) {
1386                fPos = -1;
1387        }
1388
1389        QPainter painter(this);
1390        painter.drawPixmap( ev->rect(), *m_pBackgroundPixmap, ev->rect() );
1391
1392        if (fPos != -1) {
1393                uint x = (int)( 10 + fPos * m_nGridWidth - 11 / 2 );
1394                painter.drawPixmap( QRect( x, height() / 2, 11, 8), m_tickPositionPixmap, QRect(0, 0, 11, 8) );
1395        }
1396}
1397
1398
1399
1400void SongEditorPositionRuler::updatePosition()
1401{
1402        update();
1403}
1404
1405
Note: See TracBrowser for help on using the browser.