From 5126070bb1494d81f9efc9188594a80b6574a466 Mon Sep 17 00:00:00 2001 From: "https://gitlab.com/users/CYBERDEViLNL" <1148379+CYBERDEViLNL@users.noreply.github.com> Date: Thu, 17 Jan 2019 19:07:52 +0100 Subject: [PATCH] Add basic ghost notes feature. (#4575) Lets you set a melody pattern as visible in the background of the Piano Roll as support when building a new pattern. The pattern is visible throughout the session or until cleared via the provided button. --- data/themes/classic/clear_ghost_note.png | Bin 0 -> 1088 bytes data/themes/classic/ghost_note.png | Bin 0 -> 452 bytes data/themes/classic/style.css | 4 + data/themes/default/clear_ghost_note.png | Bin 0 -> 1088 bytes data/themes/default/ghost_note.png | Bin 0 -> 3915 bytes data/themes/default/style.css | 4 + include/Pattern.h | 1 + include/PianoRoll.h | 26 ++++- src/gui/editors/PianoRoll.cpp | 121 ++++++++++++++++++++++- src/tracks/Pattern.cpp | 29 +++++- 10 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 data/themes/classic/clear_ghost_note.png create mode 100644 data/themes/classic/ghost_note.png create mode 100644 data/themes/default/clear_ghost_note.png create mode 100644 data/themes/default/ghost_note.png diff --git a/data/themes/classic/clear_ghost_note.png b/data/themes/classic/clear_ghost_note.png new file mode 100644 index 0000000000000000000000000000000000000000..c9f85a2b4ab54a5b206823b56116d87a6936d8d7 GIT binary patch literal 1088 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 ZA)oDt9LV^L_F(`3002ovPDHLkV1h83oofI9 literal 0 HcmV?d00001 diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 625d8657a..5d889295c 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -146,6 +146,10 @@ PianoRoll { qproperty-noteOpacity: 165; qproperty-noteBorders: false; /* boolean property, set false to have borderless notes */ qproperty-selectedNoteColor: #064d79; + qproperty-ghostNoteColor: #000000; + qproperty-ghostNoteTextColor: #ffffff; + qproperty-ghostNoteOpacity: 50; + qproperty-ghostNoteBorders: false; qproperty-barColor: #078f3a; qproperty-markedSemitoneColor: rgba(255, 255, 255, 30); /* Grid colors */ diff --git a/include/Pattern.h b/include/Pattern.h index eddbed313..3a1cc941c 100644 --- a/include/Pattern.h +++ b/include/Pattern.h @@ -187,6 +187,7 @@ public slots: protected slots: void openInPianoRoll(); + void setGhostInPianoRoll(); void resetName(); void changeName(); diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 8b0f1babf..168036245 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -59,7 +59,9 @@ class PianoRoll : public QWidget Q_PROPERTY( QColor lineColor READ lineColor WRITE setLineColor ) Q_PROPERTY( QColor noteModeColor READ noteModeColor WRITE setNoteModeColor ) Q_PROPERTY( QColor noteColor READ noteColor WRITE setNoteColor ) + Q_PROPERTY( QColor ghostNoteColor READ ghostNoteColor WRITE setGhostNoteColor ) Q_PROPERTY( QColor noteTextColor READ noteTextColor WRITE setNoteTextColor ) + Q_PROPERTY( QColor ghostNoteTextColor READ ghostNoteTextColor WRITE setGhostNoteTextColor ) Q_PROPERTY( QColor barColor READ barColor WRITE setBarColor ) Q_PROPERTY( QColor selectedNoteColor READ selectedNoteColor WRITE setSelectedNoteColor ) Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor ) @@ -68,6 +70,8 @@ class PianoRoll : public QWidget Q_PROPERTY( QColor markedSemitoneColor READ markedSemitoneColor WRITE setMarkedSemitoneColor ) Q_PROPERTY( int noteOpacity READ noteOpacity WRITE setNoteOpacity ) Q_PROPERTY( bool noteBorders READ noteBorders WRITE setNoteBorders ) + Q_PROPERTY( int ghostNoteOpacity READ ghostNoteOpacity WRITE setGhostNoteOpacity ) + Q_PROPERTY( bool ghostNoteBorders READ ghostNoteBorders WRITE setGhostNoteBorders ) Q_PROPERTY( QColor backgroundShade READ backgroundShade WRITE setBackgroundShade ) public: enum EditModes @@ -87,6 +91,7 @@ public: void showPanTextFloat(panning_t pan, const QPoint &pos, int timeout=-1); void setCurrentPattern( Pattern* newPattern ); + void setGhostPattern( Pattern* newPattern ); inline void stopRecording() { @@ -141,6 +146,14 @@ public: void setNoteOpacity( const int i ); bool noteBorders() const; void setNoteBorders( const bool b ); + QColor ghostNoteColor() const; + void setGhostNoteColor( const QColor & c ); + QColor ghostNoteTextColor() const; + void setGhostNoteTextColor( const QColor & c ); + int ghostNoteOpacity() const; + void setGhostNoteOpacity( const int i ); + bool ghostNoteBorders() const; + void setGhostNoteBorders( const bool b ); QColor backgroundShade() const; void setBackgroundShade( const QColor & c ); @@ -206,9 +219,12 @@ protected slots: void selectRegionFromPixels( int xStart, int xEnd ); + void clearGhostPattern(); + signals: void currentPatternChanged(); + void ghostPatternSet(bool); void semiToneMarkerMenuScaleSetEnabled(bool); void semiToneMarkerMenuChordSetEnabled(bool); @@ -309,6 +325,7 @@ private: static const QVector m_zoomLevels; Pattern* m_pattern; + Pattern* m_ghostPattern; QScrollBar * m_leftRightScroll; QScrollBar * m_topBottomScroll; @@ -388,6 +405,8 @@ private: QColor m_noteModeColor; QColor m_noteColor; QColor m_noteTextColor; + QColor m_ghostNoteColor; + QColor m_ghostNoteTextColor; QColor m_barColor; QColor m_selectedNoteColor; QColor m_textColor; @@ -395,7 +414,9 @@ private: QColor m_textShadow; QColor m_markedSemitoneColor; int m_noteOpacity; + int m_ghostNoteOpacity; bool m_noteBorders; + bool m_ghostNoteBorders; QColor m_backgroundShade; signals: @@ -412,7 +433,8 @@ public: PianoRollWindow(); const Pattern* currentPattern() const; - void setCurrentPattern(Pattern* pattern); + void setCurrentPattern( Pattern* pattern ); + void setGhostPattern( Pattern* pattern ); int quantization() const; @@ -445,6 +467,7 @@ signals: private slots: void patternRenamed(); + void ghostPatternSet( bool state ); private: void focusInEvent(QFocusEvent * event); @@ -456,6 +479,7 @@ private: ComboBox * m_noteLenComboBox; ComboBox * m_scaleComboBox; ComboBox * m_chordComboBox; + QPushButton * m_clearGhostButton; }; diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 954dde5b0..07309ec1c 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -182,6 +182,8 @@ PianoRoll::PianoRoll() : m_lineColor( 0, 0, 0 ), m_noteModeColor( 0, 0, 0 ), m_noteColor( 0, 0, 0 ), + m_ghostNoteColor( 0, 0, 0 ), + m_ghostNoteTextColor( 0, 0, 0 ), m_barColor( 0, 0, 0 ), m_selectedNoteColor( 0, 0, 0 ), m_textColor( 0, 0, 0 ), @@ -189,7 +191,9 @@ PianoRoll::PianoRoll() : m_textShadow( 0, 0, 0 ), m_markedSemitoneColor( 0, 0, 0 ), m_noteOpacity( 255 ), + m_ghostNoteOpacity( 255 ), m_noteBorders( true ), + m_ghostNoteBorders( true ), m_backgroundShade( 0, 0, 0 ) { // gui names of edit modes @@ -599,6 +603,26 @@ PianoRoll::~PianoRoll() } +void PianoRoll::setGhostPattern( Pattern* newPattern ) +{ + m_ghostPattern = newPattern; + if( newPattern != nullptr ) + { + // make sure to always get informed about the pattern being destroyed + connect( m_ghostPattern, SIGNAL( destroyedPattern( Pattern* ) ), this, SLOT( clearGhostPattern() ) ); + emit ghostPatternSet( true ); + } +} + + +void PianoRoll::clearGhostPattern() +{ + setGhostPattern( nullptr ); + emit ghostPatternSet( false ); + update(); +} + + void PianoRoll::setCurrentPattern( Pattern* newPattern ) { if( hasValidPattern() ) @@ -801,6 +825,30 @@ bool PianoRoll::noteBorders() const void PianoRoll::setNoteBorders( const bool b ) { m_noteBorders = b; } +QColor PianoRoll::ghostNoteColor() const +{ return m_ghostNoteColor; } + +void PianoRoll::setGhostNoteColor( const QColor & c ) +{ m_ghostNoteColor = c; } + +QColor PianoRoll::ghostNoteTextColor() const +{ return m_ghostNoteTextColor; } + +void PianoRoll::setGhostNoteTextColor( const QColor & c ) +{ m_ghostNoteTextColor = c; } + +int PianoRoll::ghostNoteOpacity() const +{ return m_ghostNoteOpacity; } + +void PianoRoll::setGhostNoteOpacity( const int i ) +{ m_ghostNoteOpacity = i; } + +bool PianoRoll::ghostNoteBorders() const +{ return m_ghostNoteBorders; } + +void PianoRoll::setGhostNoteBorders( const bool b ) +{ m_ghostNoteBorders = b; } + QColor PianoRoll::backgroundShade() const { return m_backgroundShade; } @@ -810,7 +858,6 @@ void PianoRoll::setBackgroundShade( const QColor & c ) - void PianoRoll::drawNoteRect( QPainter & p, int x, int y, int width, const Note * n, const QColor & noteCol, const QColor & noteTextColor, const QColor & selCol, const int noteOpc, const bool borders, bool drawNoteName ) @@ -3024,6 +3071,50 @@ void PianoRoll::paintEvent(QPaintEvent * pe ) QPolygonF editHandles; + // -- Begin ghost pattern + if( m_ghostPattern != nullptr && m_ghostPattern != m_pattern ) + { + for( const Note *note : m_ghostPattern->notes() ) + { + int len_ticks = note->length(); + + if( len_ticks == 0 ) + { + continue; + } + else if( len_ticks < 0 ) + { + len_ticks = 4; + } + const int key = note->key() - m_startKey + 1; + + int pos_ticks = note->pos(); + + int note_width = len_ticks * m_ppt / MidiTime::ticksPerTact(); + const int x = ( pos_ticks - m_currentPosition ) * + m_ppt / MidiTime::ticksPerTact(); + // skip this note if not in visible area at all + if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) ) + { + continue; + } + + // is the note in visible area? + if( key > 0 && key <= visible_keys ) + { + + // we've done and checked all, let's draw the + // note + drawNoteRect( p, x + WHITE_KEY_WIDTH, + y_base - key * KEY_LINE_HEIGHT, + note_width, note, ghostNoteColor(), ghostNoteTextColor(), selectedNoteColor(), + ghostNoteOpacity(), ghostNoteBorders(), drawNoteNames ); + } + + } + } + // -- End ghost pattern + for( const Note *note : m_pattern->notes() ) { int len_ticks = note->length(); @@ -4221,8 +4312,15 @@ PianoRollWindow::PianoRollWindow() : m_chordComboBox = new ComboBox( m_toolBar ); m_chordComboBox->setModel( &m_editor->m_chordModel ); m_chordComboBox->setFixedSize( 105, 22 ); - m_chordComboBox->setToolTip( tr( "Chord") ); + m_chordComboBox->setToolTip( tr( "Chord" ) ); + // -- Clear ghost pattern button + m_clearGhostButton = new QPushButton( m_toolBar ); + m_clearGhostButton->setIcon( embed::getIconPixmap( "clear_ghost_note" ) ); + m_clearGhostButton->setToolTip( tr( "Clear ghost notes" ) ); + m_clearGhostButton->setEnabled( false ); + connect( m_clearGhostButton, SIGNAL( clicked() ), m_editor, SLOT( clearGhostPattern() ) ); + connect( m_editor, SIGNAL( ghostPatternSet( bool ) ), this, SLOT( ghostPatternSet( bool ) ) ); zoomAndNotesToolBar->addWidget( zoom_lbl ); zoomAndNotesToolBar->addWidget( m_zoomingComboBox ); @@ -4243,6 +4341,9 @@ PianoRollWindow::PianoRollWindow() : zoomAndNotesToolBar->addWidget( chord_lbl ); zoomAndNotesToolBar->addWidget( m_chordComboBox ); + zoomAndNotesToolBar->addSeparator(); + zoomAndNotesToolBar->addWidget( m_clearGhostButton ); + // setup our actual window setFocusPolicy( Qt::StrongFocus ); setFocus(); @@ -4265,6 +4366,14 @@ const Pattern* PianoRollWindow::currentPattern() const +void PianoRollWindow::setGhostPattern( Pattern* pattern ) +{ + m_editor->setGhostPattern( pattern ); +} + + + + void PianoRollWindow::setCurrentPattern( Pattern* pattern ) { m_editor->setCurrentPattern( pattern ); @@ -4387,6 +4496,14 @@ void PianoRollWindow::patternRenamed() +void PianoRollWindow::ghostPatternSet( bool state ) +{ + m_clearGhostButton->setEnabled( state ); +} + + + + void PianoRollWindow::focusInEvent( QFocusEvent * event ) { // when the window is given focus, also give focus to the actual piano roll diff --git a/src/tracks/Pattern.cpp b/src/tracks/Pattern.cpp index 05d316f00..d5da06df7 100644 --- a/src/tracks/Pattern.cpp +++ b/src/tracks/Pattern.cpp @@ -637,6 +637,18 @@ void PatternView::openInPianoRoll() + +void PatternView::setGhostInPianoRoll() +{ + gui->pianoRoll()->setGhostPattern( m_pat ); + gui->pianoRoll()->parentWidget()->show(); + gui->pianoRoll()->show(); + gui->pianoRoll()->setFocus(); +} + + + + void PatternView::resetName() { m_pat->setName( m_pat->m_instrumentTrack->name() ); @@ -663,7 +675,22 @@ void PatternView::constructContextMenu( QMenu * _cm ) _cm->insertAction( _cm->actions()[0], a ); connect( a, SIGNAL( triggered( bool ) ), this, SLOT( openInPianoRoll() ) ); - _cm->insertSeparator( _cm->actions()[1] ); + + if( gui->pianoRoll()->currentPattern() && + gui->pianoRoll()->currentPattern() != m_pat && + not m_pat->empty() ) + { + QAction * b = new QAction( embed::getIconPixmap( "ghost_note" ), + tr( "Set as ghost in piano-roll" ), _cm ); + _cm->insertAction( _cm->actions()[1], b ); + connect( b, SIGNAL( triggered( bool ) ), + this, SLOT( setGhostInPianoRoll() ) ); + _cm->insertSeparator( _cm->actions()[2] ); + } + else + { + _cm->insertSeparator( _cm->actions()[1] ); + } _cm->addSeparator();