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
zcmV-G1i$-
3$EDcV9eqd5WEs3QhATg7e
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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();