Skip to content

Commit

Permalink
Add basic ghost notes feature. (LMMS#4575)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
https://gitlab.com/users/CYBERDEViLNL authored and zonkmachine committed Jan 17, 2019
1 parent df36333 commit f7761d6
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 4 deletions.
Binary file added data/themes/classic/clear_ghost_note.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/themes/classic/ghost_note.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions data/themes/classic/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ PianoRoll {
qproperty-noteOpacity: 128;
qproperty-noteBorders: true; /* boolean property, set false to have borderless notes */
qproperty-selectedNoteColor: rgb( 0, 125, 255 );
qproperty-ghostNoteColor: #000000;
qproperty-ghostNoteTextColor: #ffffff;
qproperty-ghostNoteOpacity: 50;
qproperty-ghostNoteBorders: true;
qproperty-barColor: #4afd85;
qproperty-markedSemitoneColor: rgba( 0, 255, 200, 60 );
/* Grid colors */
Expand Down
Binary file added data/themes/default/clear_ghost_note.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/themes/default/ghost_note.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions data/themes/default/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions include/Pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ public slots:

protected slots:
void openInPianoRoll();
void setGhostInPianoRoll();

void resetName();
void changeName();
Expand Down
26 changes: 25 additions & 1 deletion include/PianoRoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -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
Expand All @@ -87,6 +91,7 @@ class PianoRoll : public QWidget
void showPanTextFloat(panning_t pan, const QPoint &pos, int timeout=-1);

void setCurrentPattern( Pattern* newPattern );
void setGhostPattern( Pattern* newPattern );

inline void stopRecording()
{
Expand Down Expand Up @@ -141,6 +146,14 @@ class PianoRoll : public QWidget
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 );

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -309,6 +325,7 @@ protected slots:
static const QVector<double> m_zoomLevels;

Pattern* m_pattern;
Pattern* m_ghostPattern;
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;

Expand Down Expand Up @@ -388,14 +405,18 @@ protected slots:
QColor m_noteModeColor;
QColor m_noteColor;
QColor m_noteTextColor;
QColor m_ghostNoteColor;
QColor m_ghostNoteTextColor;
QColor m_barColor;
QColor m_selectedNoteColor;
QColor m_textColor;
QColor m_textColorLight;
QColor m_textShadow;
QColor m_markedSemitoneColor;
int m_noteOpacity;
int m_ghostNoteOpacity;
bool m_noteBorders;
bool m_ghostNoteBorders;
QColor m_backgroundShade;

signals:
Expand All @@ -412,7 +433,8 @@ class PianoRollWindow : public Editor, SerializingObject
PianoRollWindow();

const Pattern* currentPattern() const;
void setCurrentPattern(Pattern* pattern);
void setCurrentPattern( Pattern* pattern );
void setGhostPattern( Pattern* pattern );

int quantization() const;

Expand Down Expand Up @@ -445,6 +467,7 @@ class PianoRollWindow : public Editor, SerializingObject

private slots:
void patternRenamed();
void ghostPatternSet( bool state );

private:
void focusInEvent(QFocusEvent * event);
Expand All @@ -456,6 +479,7 @@ private slots:
ComboBox * m_noteLenComboBox;
ComboBox * m_scaleComboBox;
ComboBox * m_chordComboBox;
QPushButton * m_clearGhostButton;

};

Expand Down
121 changes: 119 additions & 2 deletions src/gui/editors/PianoRoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,18 @@ 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 ),
m_textColorLight( 0, 0, 0 ),
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
Expand Down Expand Up @@ -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() )
Expand Down Expand Up @@ -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; }

Expand All @@ -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 )
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 );
Expand All @@ -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();
Expand All @@ -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 );
Expand Down Expand Up @@ -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
Expand Down
29 changes: 28 additions & 1 deletion src/tracks/Pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() );
Expand All @@ -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();

Expand Down

0 comments on commit f7761d6

Please sign in to comment.