From 680d75ff69743a3a84b94431ebf2f782348bd194 Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 15 May 2019 19:43:22 +0200 Subject: [PATCH 01/67] Mostly working --- include/MidiTime.h | 3 +-- include/SongEditor.h | 3 +++ src/core/Track.cpp | 8 +++---- src/core/midi/MidiTime.cpp | 20 +++++++++++------ src/gui/TimeLineWidget.cpp | 6 ++--- src/gui/editors/SongEditor.cpp | 40 +++++++++++++++++++++++++++++++--- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/include/MidiTime.h b/include/MidiTime.h index 7aaacf96344..0e8015e04cf 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -63,7 +63,7 @@ class LMMS_EXPORT MidiTime MidiTime( const tact_t tact, const tick_t ticks ); MidiTime( const tick_t ticks = 0 ); - MidiTime toNearestTact() const; + MidiTime quantize(float) const; MidiTime toAbsoluteTact() const; MidiTime& operator+=( const MidiTime& time ); @@ -110,4 +110,3 @@ class LMMS_EXPORT MidiTime #endif - diff --git a/include/SongEditor.h b/include/SongEditor.h index f9b6aad1b56..02bc523f295 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -73,6 +73,7 @@ class SongEditor : public TrackContainerView void loadSettings( const QDomElement& element ); ComboBoxModel *zoomingModel() const; + float getSnapSize() const; public slots: void scrolled( int new_pos ); @@ -130,6 +131,7 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; + ComboBoxModel* m_snappingModel; static const QVector m_zoomLevels; @@ -188,6 +190,7 @@ protected slots: QAction* m_crtlAction; ComboBox * m_zoomingComboBox; + ComboBox * m_snappingComboBox; }; #endif diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 64c17c9e8ec..5f8c84f9431 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -897,7 +897,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.toNearestTact(); + t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -920,7 +920,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime::ticksPerTact() / ppt ) ); if( snap ) { - dtick = dtick.toNearestTact(); + dtick = dtick.quantize( gui->songEditor()->m_editor->getSnapSize() ); } // find out smallest position of all selected objects for not // moving an object before zero @@ -956,7 +956,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = qMax( MidiTime::ticksPerTact(), t.toNearestTact() ); + t = qMax( MidiTime::ticksPerTact(), t.quantize( gui->songEditor()->m_editor->getSnapSize() ) ); } m_tco->changeLength( t ); } @@ -974,7 +974,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.toNearestTact(); + t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } MidiTime oldPos = m_tco->startPosition(); if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() ) diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index b4607aee9c3..7dbbf19ebaf 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -63,13 +63,19 @@ MidiTime::MidiTime( const tick_t ticks ) : { } -MidiTime MidiTime::toNearestTact() const -{ - if( m_ticks % s_ticksPerTact >= s_ticksPerTact/2 ) - { - return ( getTact() + 1 ) * s_ticksPerTact; - } - return getTact() * s_ticksPerTact; +MidiTime MidiTime::quantize(float bars) const +{ + //float bars = 0.5; + //The intervals we should snap to, our new position should be a factor of this + int interval = s_ticksPerTact * bars; + //The lower position we could snap to + int lowPos = m_ticks / interval; + //Offset from the lower position + int offset = m_ticks % interval; + //1 if we should snap up, 0 if we shouldn't + int snapUp = offset / (interval / 2); + + return (lowPos + snapUp) * interval; } diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 9c2f3855997..6523bc533a3 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -2,7 +2,7 @@ * TimeLineWidget.cpp - class timeLine, representing a time-line with position marker * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of LMMS - https://lmms.io * * This program is free software; you can redistribute it and/or @@ -382,14 +382,14 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) } else { - m_loopPos[i] = t.toNearestTact(); + m_loopPos[i] = t.quantize(1.0); } // Catch begin == end if( m_loopPos[0] == m_loopPos[1] ) { // Note, swap 1 and 0 below and the behavior "skips" the other // marking instead of pushing it. - if( m_action == MoveLoopBegin ) + if( m_action == MoveLoopBegin ) m_loopPos[0] -= MidiTime::ticksPerTact(); else m_loopPos[1] += MidiTime::ticksPerTact(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index b397434b102..57673a42927 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "AutomatableSlider.h" #include "ComboBox.h" @@ -76,11 +77,13 @@ SongEditor::SongEditor( Song * song ) : TrackContainerView( song ), m_song( song ), m_zoomingModel(new ComboBoxModel()), + m_snappingModel(new ComboBoxModel()), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) { m_zoomingModel->setParent(this); + m_snappingModel->setParent(this); // create time-line m_widgetWidthTotal = ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt()==1 ? @@ -230,7 +233,7 @@ SongEditor::SongEditor( Song * song ) : connect( m_song, SIGNAL( lengthChanged( int ) ), this, SLOT( updateScrollBar( int ) ) ); - // Set up zooming model + //Set up zooming model for( float const & zoomLevel : m_zoomLevels ) { m_zoomingModel->addItem( QString( "%1\%" ).arg( zoomLevel * 100 ) ); @@ -240,6 +243,20 @@ SongEditor::SongEditor( Song * song ) : connect( m_zoomingModel, SIGNAL( dataChanged() ), this, SLOT( zoomingChanged() ) ); + //Set up snapping model, 2^i + for ( int i = 3; i >= -4; i-- ){ + if ( i > 0 ){ + m_snappingModel->addItem( QString( "%1 Bars").arg( 1 << i ) ); + } + else if ( i == 0 ){ + m_snappingModel->addItem( "1 Bar" ); + } + else { + m_snappingModel->addItem( QString( "1/%1 Bar" ).arg( 1 << (-i) ) ); + } + } + m_snappingModel->setInitValue( m_snappingModel->findText( "1 Bar" ) ); + setFocusPolicy( Qt::StrongFocus ); setFocus(); } @@ -261,7 +278,15 @@ void SongEditor::loadSettings( const QDomElement& element ) MainWindow::restoreWidgetState(parentWidget(), element); } - +float SongEditor::getSnapSize() const{ + int val = -m_snappingModel->value() + 3; + if ( val >= 0 ){ + return 1 << val; + } + else { + return 1.0 / ( 1 << abs(val) ); + } +} void SongEditor::setHighQuality( bool hq ) @@ -718,7 +743,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QLabel * zoom_lbl = new QLabel( m_toolBar ); zoom_lbl->setPixmap( embed::getIconPixmap( "zoom" ) ); - // setup zooming-stuff + //Set up zooming-stuff m_zoomingComboBox = new ComboBox( m_toolBar ); m_zoomingComboBox->setFixedSize( 80, 22 ); m_zoomingComboBox->move( 580, 4 ); @@ -728,6 +753,15 @@ SongEditorWindow::SongEditorWindow(Song* song) : zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); + //Set up quantization/snapping selector + m_snappingComboBox = new ComboBox( m_toolBar ); + m_snappingComboBox->setFixedSize( 80, 22 ); + //m_snappingComboBox->move( 580 + 80 + 100, 4 ); + m_snappingComboBox->setModel(m_editor->m_snappingModel); + m_snappingComboBox->setToolTip(tr("Clip snapping")); + + zoomToolBar->addWidget( m_snappingComboBox ); + connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); } From 831cb645580e9ec577bea4d8a9c047a4d3226db9 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:15:53 +0200 Subject: [PATCH 02/67] Simplify and fix snapping for pattern cloning --- src/core/Track.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 5f8c84f9431..5fbe5327f8b 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -524,7 +524,7 @@ void TrackContentObjectView::updatePosition() void TrackContentObjectView::dragEnterEvent( QDragEnterEvent * dee ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition().getTact(), 0 ); + MidiTime tcoPos = MidiTime( m_tco->startPosition() ); if( tcw->canPasteSelection( tcoPos, dee ) == false ) { dee->ignore(); @@ -563,7 +563,7 @@ void TrackContentObjectView::dropEvent( QDropEvent * de ) if( m_trackView->trackContainerView()->allowRubberband() == true ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition().getTact(), 0 ); + MidiTime tcoPos = MidiTime( m_tco->startPosition() ); if( tcw->pasteSelection( tcoPos, de ) == true ) { de->accept(); @@ -1399,6 +1399,7 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { + tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); @@ -1517,6 +1518,10 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // TODO -- Need to draw the hovericon either way, or ghost the TCOs // onto their final position. + // All patterns should be offset the same amount as the grabbed pattern + // The offset is quantized (rather than the positions) to preserve fine adjustments + int offset = MidiTime(tcoPos - grabbedTCOPos).quantize(gui->songEditor()->m_editor->getSnapSize()); + for( int i = 0; icreateTCO( pos ); tco->restoreState( tcoElement ); @@ -1562,7 +1562,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) */ void TrackContentWidget::dropEvent( QDropEvent * de ) { - MidiTime tcoPos = MidiTime( getPosition( de->pos().x() ).getTact(), 0 ); + MidiTime tcoPos = MidiTime( getPosition( de->pos().x() ) ); if( pasteSelection( tcoPos, de ) == true ) { de->accept(); From 123c8da51636381980849a2e5af844bf98404732 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:22:06 +0200 Subject: [PATCH 03/67] Add icon --- src/core/Track.cpp | 2 +- src/gui/editors/SongEditor.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 5fbe5327f8b..b72b9fe80a8 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1532,7 +1532,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) Track * t = tracks.at( finalTrackIndex ); // The new position is the old position plus the offset. - MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + snappedOffset; + MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset; TrackContentObject * tco = t->createTCO( pos ); tco->restoreState( tcoElement ); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 57673a42927..e040388f105 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -753,14 +753,18 @@ SongEditorWindow::SongEditorWindow(Song* song) : zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); + DropToolBar *snapToolBar = addDropToolBarToTop(tr("Snap controls")); + QLabel * snap_lbl = new QLabel( m_toolBar ); + snap_lbl->setPixmap( embed::getIconPixmap( "quantize" ) ); + //Set up quantization/snapping selector m_snappingComboBox = new ComboBox( m_toolBar ); m_snappingComboBox->setFixedSize( 80, 22 ); - //m_snappingComboBox->move( 580 + 80 + 100, 4 ); m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - zoomToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addWidget( snap_lbl ); + snapToolBar->addWidget( m_snappingComboBox ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); From 70a3612e43773735dbfb7c22d8f327d183c7de30 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:46:23 +0200 Subject: [PATCH 04/67] Adaptive Snap --- include/SongEditor.h | 3 +++ src/gui/editors/SongEditor.cpp | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 02bc523f295..89ed4e7ce89 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -81,6 +81,7 @@ public slots: void setEditMode( EditMode mode ); void setEditModeDraw(); void setEditModeSelect(); + void toggleAdaptiveSnap(); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -132,6 +133,7 @@ private slots: ComboBoxModel* m_zoomingModel; ComboBoxModel* m_snappingModel; + bool m_adaptiveSnap; static const QVector m_zoomLevels; @@ -183,6 +185,7 @@ protected slots: QAction* m_addBBTrackAction; QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; + QAction* m_setAdaptiveSnapAction; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index e040388f105..2a5b9e982ee 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -78,6 +78,7 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), + m_adaptiveSnap( true ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -280,11 +281,15 @@ void SongEditor::loadSettings( const QDomElement& element ) float SongEditor::getSnapSize() const{ int val = -m_snappingModel->value() + 3; + if (m_adaptiveSnap){ + val = val - m_zoomingModel->value() + 3; + } + if ( val >= 0 ){ return 1 << val; } else { - return 1.0 / ( 1 << abs(val) ); + return 1.0 / ( 1 << -val ); } } @@ -323,6 +328,11 @@ void SongEditor::setEditModeSelect() setEditMode(SelectMode); } +void SongEditor::toggleAdaptiveSnap() +{ + m_adaptiveSnap = !m_adaptiveSnap; +} + @@ -763,8 +773,16 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); + m_setAdaptiveSnapAction = new QAction(embed::getIconPixmap("add_automation"), + tr("Enable adaptive snap"), this); + m_setAdaptiveSnapAction->setCheckable(true); + m_setAdaptiveSnapAction->setChecked(true); + + connect(m_setAdaptiveSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleAdaptiveSnap())); + snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addAction( m_setAdaptiveSnapAction ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); From dde4daae6e9509b08ec1435772f9528f30cd900e Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 18:04:06 +0200 Subject: [PATCH 05/67] Fix potential crash by capping snap fineness. Add space between adaptive snap dropdown and button --- src/gui/editors/SongEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 2a5b9e982ee..1e1bc561190 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -280,10 +280,13 @@ void SongEditor::loadSettings( const QDomElement& element ) } float SongEditor::getSnapSize() const{ + // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; + // If adaptive snap is on, we snap to finer values when zoomed in if (m_adaptiveSnap){ val = val - m_zoomingModel->value() + 3; } + val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. if ( val >= 0 ){ return 1 << val; @@ -782,6 +785,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addSeparator(); snapToolBar->addAction( m_setAdaptiveSnapAction ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); From 54270a7da85bac4ab4eb5c2cc38e9e483e02dce9 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 18:53:08 +0200 Subject: [PATCH 06/67] Fix cloning of short patterns --- src/core/Track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index b72b9fe80a8..87bfe25b5e1 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1399,7 +1399,7 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { - tcoPos = MidiTime(tcoPos.getTact(), 0); + //tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); From d5e7f109f0519e211fddeb5b3844237da1119830 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 19:38:03 +0200 Subject: [PATCH 07/67] Widen song editor's default size, remove unused lines --- src/core/Track.cpp | 2 -- src/gui/editors/SongEditor.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 87bfe25b5e1..0eb12269885 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1399,7 +1399,6 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { - //tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); @@ -1497,7 +1496,6 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) int initialTrackIndex = tiAttr.value().toInt(); QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - MidiTime grabbedTCOTact = MidiTime( grabbedTCOPos.getTact(), 0 ); // Snap the mouse position to the beginning of the dropped tact, in ticks const TrackContainer::TrackList tracks = getTrack()->trackContainer()->tracks(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 1e1bc561190..16dd6c233ec 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -794,7 +794,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {600, 300}; + return {640, 300}; } From 04d3d35d8f63c5a06c4584b6792b33e89e3bb6e7 Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 17 May 2019 20:26:13 +0200 Subject: [PATCH 08/67] Preserve offsets! --- include/Track.h | 8 ++++---- src/core/Track.cpp | 18 +++++++++++------- src/core/midi/MidiTime.cpp | 1 - 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/Track.h b/include/Track.h index 1267d2ef742..31e91be1acb 100644 --- a/include/Track.h +++ b/include/Track.h @@ -236,7 +236,7 @@ class TrackContentObjectView : public selectableObject, public ModelView // access needsUpdate member variable bool needsUpdate(); void setNeedsUpdate( bool b ); - + public slots: virtual bool close(); void cut(); @@ -564,13 +564,13 @@ class LMMS_EXPORT Track : public Model, public JournallingObject using Model::dataChanged; - inline int getHeight() + inline int getHeight() { return m_height >= MINIMAL_TRACK_HEIGHT - ? m_height + ? m_height : DEFAULT_TRACK_HEIGHT; } - inline void setHeight( int height ) + inline void setHeight( int height ) { m_height = height; } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 0eb12269885..90885eccf7a 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -889,17 +889,18 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); - MidiTime t = qMax( 0, (int) - m_trackView->trackContainerView()->currentPosition()+ - static_cast( x * MidiTime::ticksPerTact() / - ppt ) ); + const int mousePixPos = mapToParent( me->pos() ).x(); + MidiTime mousePos = static_cast( mousePixPos * MidiTime::ticksPerTact() / ppt ); + MidiTime mouseStart = static_cast( mapToParent(m_initialMousePos).x() * MidiTime::ticksPerTact() / ppt ); + MidiTime offset = mousePos - mouseStart; + if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); + offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - m_tco->movePosition( t ); + + m_tco->movePosition( m_tco->startPosition() + offset ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). arg( m_tco->startPosition().getTact() + 1 ). @@ -1531,6 +1532,9 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // The new position is the old position plus the offset. MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset; + // If we land on ourselves, offset by one snap + MidiTime shift = MidiTime::ticksPerTact() * gui->songEditor()->m_editor->getSnapSize(); + if (offset == 0) { pos += shift; } TrackContentObject * tco = t->createTCO( pos ); tco->restoreState( tcoElement ); diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index 7dbbf19ebaf..82ed642ba78 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -65,7 +65,6 @@ MidiTime::MidiTime( const tick_t ticks ) : MidiTime MidiTime::quantize(float bars) const { - //float bars = 0.5; //The intervals we should snap to, our new position should be a factor of this int interval = s_ticksPerTact * bars; //The lower position we could snap to From 0f94d790fb3dadb3151f0eebe51c7d51c51cd647 Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 17 May 2019 20:33:49 +0200 Subject: [PATCH 09/67] Clamp position to be non-negative --- src/core/Track.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 90885eccf7a..59fa1f57e77 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -900,7 +900,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - m_tco->movePosition( m_tco->startPosition() + offset ); + MidiTime newPos = max(0, m_tco->startPosition() + offset); + m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). arg( m_tco->startPosition().getTact() + 1 ). From ee771921521c9c50c940933d7cfc5219862c70a0 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 18 May 2019 11:54:04 +0200 Subject: [PATCH 10/67] Snap modes for single clip move --- include/SongEditor.h | 23 ++++++++++++++++--- include/Track.h | 4 +++- src/core/Track.cpp | 35 ++++++++++++++++++---------- src/gui/editors/SongEditor.cpp | 42 +++++++++++++++++++++++----------- 4 files changed, 75 insertions(+), 29 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 89ed4e7ce89..e52f40fb3f9 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -32,6 +32,7 @@ #include "ActionGroup.h" #include "Editor.h" #include "TrackContainerView.h" +#include "NStateButton.h" class QLabel; class QScrollBar; @@ -66,6 +67,13 @@ class SongEditor : public TrackContainerView SelectMode }; + enum SnapType + { + ShiftMode, + SnapMode, + BothMode + }; + SongEditor( Song * song ); ~SongEditor(); @@ -74,6 +82,10 @@ class SongEditor : public TrackContainerView ComboBoxModel *zoomingModel() const; float getSnapSize() const; + SnapType snapType() const + { + return m_snapType; + } public slots: void scrolled( int new_pos ); @@ -81,7 +93,8 @@ public slots: void setEditMode( EditMode mode ); void setEditModeDraw(); void setEditModeSelect(); - void toggleAdaptiveSnap(); + void toggleProportionalSnap(); + void setSnapMode( int ); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -132,8 +145,11 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; + ComboBoxModel* m_snappingModel; - bool m_adaptiveSnap; + bool m_proportionalSnap; + + SnapType m_snapType; static const QVector m_zoomLevels; @@ -185,7 +201,8 @@ protected slots: QAction* m_addBBTrackAction; QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; - QAction* m_setAdaptiveSnapAction; + QAction* m_setProportionalSnapAction; + NStateButton* m_snapTypeButton; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/include/Track.h b/include/Track.h index 31e91be1acb..e94f0ba51f1 100644 --- a/include/Track.h +++ b/include/Track.h @@ -297,6 +297,7 @@ protected slots: Actions m_action; QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; + MidiTime m_initialTCOPos; TextFloat * m_hint; @@ -311,10 +312,11 @@ protected slots: bool m_gradient; bool m_needsUpdate; - inline void setInitialMousePos( QPoint pos ) + inline void setInitialPos( QPoint pos ) { m_initialMousePos = pos; m_initialMouseGlobalPos = mapToGlobal( pos ); + m_initialTCOPos = m_tco->startPosition(); } bool mouseMovedDistance( QMouseEvent * me, int distance ); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 59fa1f57e77..f7bf227fdc0 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -267,6 +267,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_action( NoAction ), m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), + m_initialTCOPos( MidiTime(0) ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), m_mutedBackgroundColor( 0, 0, 0 ), @@ -711,7 +712,7 @@ void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & pai */ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) { - setInitialMousePos( me->pos() ); + setInitialPos( me->pos() ); if( !fixedTCOs() && me->button() == Qt::LeftButton ) { if( me->modifiers() & Qt::ControlModifier ) @@ -739,7 +740,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) // move or resize m_tco->setJournalling( false ); - setInitialMousePos( me->pos() ); + setInitialPos( me->pos() ); SampleTCO * sTco = dynamic_cast( m_tco ); if( me->x() < RESIZE_GRIP_WIDTH && sTco @@ -889,23 +890,33 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int mousePixPos = mapToParent( me->pos() ).x(); - MidiTime mousePos = static_cast( mousePixPos * MidiTime::ticksPerTact() / ppt ); - MidiTime mouseStart = static_cast( mapToParent(m_initialMousePos).x() * MidiTime::ticksPerTact() / ppt ); - MidiTime offset = mousePos - mouseStart; - + const int pixPos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = pixPos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If ctrl isn't held, we need to quantize if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + MidiTime snapPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + MidiTime shiftPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + switch ( gui->songEditor()->m_editor->snapType() ){ + case SongEditor::SnapMode : newPos = snapPos; break; + case SongEditor::ShiftMode: newPos = shiftPos; break; + default: + if ( abs(newPos - snapPos) < abs(newPos - shiftPos) ){ + newPos = snapPos; + } + else { + newPos = shiftPos; + } + } } - - MidiTime newPos = max(0, m_tco->startPosition() + offset); + newPos = max(0, static_cast(newPos)); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). - arg( m_tco->startPosition().getTact() + 1 ). - arg( m_tco->startPosition().getTicks() % + arg( newPos.getTact() + 1 ). + arg( newPos.getTicks() % MidiTime::ticksPerTact() ) ); s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) ); } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 16dd6c233ec..b34979ff3fc 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -78,7 +78,8 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), - m_adaptiveSnap( true ), + m_proportionalSnap( true ), + m_snapType( ShiftMode ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -282,8 +283,8 @@ void SongEditor::loadSettings( const QDomElement& element ) float SongEditor::getSnapSize() const{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; - // If adaptive snap is on, we snap to finer values when zoomed in - if (m_adaptiveSnap){ + // If proportional snap is on, we snap to finer values when zoomed in + if (m_proportionalSnap){ val = val - m_zoomingModel->value() + 3; } val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. @@ -331,9 +332,14 @@ void SongEditor::setEditModeSelect() setEditMode(SelectMode); } -void SongEditor::toggleAdaptiveSnap() +void SongEditor::toggleProportionalSnap() { - m_adaptiveSnap = !m_adaptiveSnap; + m_proportionalSnap = !m_proportionalSnap; +} + +void SongEditor::setSnapMode( int state ) +{ + m_snapType = static_cast( state ); } @@ -776,17 +782,27 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - m_setAdaptiveSnapAction = new QAction(embed::getIconPixmap("add_automation"), - tr("Enable adaptive snap"), this); - m_setAdaptiveSnapAction->setCheckable(true); - m_setAdaptiveSnapAction->setChecked(true); - - connect(m_setAdaptiveSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleAdaptiveSnap())); + m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), + tr("Toggle roportional snap on/off"), this); + m_setProportionalSnapAction->setCheckable(true); + m_setProportionalSnapAction->setChecked(true); + connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); + + NStateButton * m_snapTypeButton = new NStateButton( m_toolBar ); + m_snapTypeButton->addState( embed::getIconPixmap( "back_to_start" ), + tr( "Shift mode" ) ); + m_snapTypeButton->addState( embed::getIconPixmap( "back_to_zero" ), + tr( "Snap mode" ) ); + m_snapTypeButton->addState( embed::getIconPixmap( "keep_stop_position" ), + tr( "Snap & shift mode" ) ); + connect( m_snapTypeButton, SIGNAL( changedState( int ) ), m_editor, + SLOT( setSnapMode( int ) ) ); snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); - snapToolBar->addAction( m_setAdaptiveSnapAction ); + snapToolBar->addAction( m_setProportionalSnapAction ); + snapToolBar->addWidget( m_snapTypeButton ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); @@ -794,7 +810,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {640, 300}; + return {660, 300}; } From 4fa3d485d0961fab66ebea89b4759b81bc61b539 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 19:29:56 +0200 Subject: [PATCH 11/67] Use modifier keys instead of toggle for snap behavior, allow different snapping for selections, allow alt for fine movement --- include/SongEditor.h | 16 ----- include/Track.h | 2 + src/core/Track.cpp | 120 ++++++++++++++++++++------------- src/gui/editors/SongEditor.cpp | 19 +----- 4 files changed, 76 insertions(+), 81 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index e52f40fb3f9..1f70bece479 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -32,7 +32,6 @@ #include "ActionGroup.h" #include "Editor.h" #include "TrackContainerView.h" -#include "NStateButton.h" class QLabel; class QScrollBar; @@ -67,13 +66,6 @@ class SongEditor : public TrackContainerView SelectMode }; - enum SnapType - { - ShiftMode, - SnapMode, - BothMode - }; - SongEditor( Song * song ); ~SongEditor(); @@ -82,10 +74,6 @@ class SongEditor : public TrackContainerView ComboBoxModel *zoomingModel() const; float getSnapSize() const; - SnapType snapType() const - { - return m_snapType; - } public slots: void scrolled( int new_pos ); @@ -94,7 +82,6 @@ public slots: void setEditModeDraw(); void setEditModeSelect(); void toggleProportionalSnap(); - void setSnapMode( int ); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -149,8 +136,6 @@ private slots: ComboBoxModel* m_snappingModel; bool m_proportionalSnap; - SnapType m_snapType; - static const QVector m_zoomLevels; bool m_scrollBack; @@ -202,7 +187,6 @@ protected slots: QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; QAction* m_setProportionalSnapAction; - NStateButton* m_snapTypeButton; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/include/Track.h b/include/Track.h index e94f0ba51f1..3c1d3ad5d64 100644 --- a/include/Track.h +++ b/include/Track.h @@ -298,6 +298,7 @@ protected slots: QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; MidiTime m_initialTCOPos; + QVector m_initialOffsets; TextFloat * m_hint; @@ -318,6 +319,7 @@ protected slots: m_initialMouseGlobalPos = mapToGlobal( pos ); m_initialTCOPos = m_tco->startPosition(); } + void setInitialOffsets(); bool mouseMovedDistance( QMouseEvent * me, int distance ); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f7bf227fdc0..f8e7c3af2a6 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "AutomationPattern.h" @@ -268,6 +269,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), m_initialTCOPos( MidiTime(0) ), + m_initialOffsets( QVector() ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), m_mutedBackgroundColor( 0, 0, 0 ), @@ -713,6 +715,7 @@ void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & pai void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) { setInitialPos( me->pos() ); + setInitialOffsets(); if( !fixedTCOs() && me->button() == Qt::LeftButton ) { if( me->modifiers() & Qt::ControlModifier ) @@ -726,7 +729,9 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) m_action = ToggleSelected; } } - else if( !me->modifiers() ) + else if( !me->modifiers() + || (me->modifiers() & Qt::AltModifier) + || (me->modifiers() & Qt::ShiftModifier) ) { if( isSelected() ) { @@ -741,6 +746,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) m_tco->setJournalling( false ); setInitialPos( me->pos() ); + setInitialOffsets(); SampleTCO * sTco = dynamic_cast( m_tco ); if( me->x() < RESIZE_GRIP_WIDTH && sTco @@ -890,27 +896,24 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int pixPos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = pixPos * MidiTime::ticksPerTact() / ppt; + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; - // If ctrl isn't held, we need to quantize - if( ! ( me->modifiers() & Qt::ControlModifier ) - && me->button() == Qt::NoButton ) - { - MidiTime snapPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - MidiTime shiftPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - switch ( gui->songEditor()->m_editor->snapType() ){ - case SongEditor::SnapMode : newPos = snapPos; break; - case SongEditor::ShiftMode: newPos = shiftPos; break; - default: - if ( abs(newPos - snapPos) < abs(newPos - shiftPos) ){ - newPos = snapPos; - } - else { - newPos = shiftPos; - } - } + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + newPos = max(0, static_cast(newPos)); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); @@ -922,44 +925,49 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == MoveSelection ) { - const int dx = me->x() - m_initialMousePos.x(); - const bool snap = !(me->modifiers() & Qt::ControlModifier) && - me->button() == Qt::NoButton; + // 1: Find the position we want to move the grabbed TCO to + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + + // 2: Handle moving the other selected TCOs the same distance QVector so = m_trackView->trackContainerView()->selectedObjects(); - QVector tcos; - int smallestPos = 0; - MidiTime dtick = MidiTime( static_cast( dx * - MidiTime::ticksPerTact() / ppt ) ); - if( snap ) - { - dtick = dtick.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - // find out smallest position of all selected objects for not - // moving an object before zero + QVector tcos; // List of selected clips + int leftmost = 0; // Leftmost clip's offset from grabbed clip + // Populate tcos, find leftmost for( QVector::iterator it = so.begin(); it != so.end(); ++it ) { TrackContentObjectView * tcov = dynamic_cast( *it ); - if( tcov == NULL ) - { - continue; - } - TrackContentObject * tco = tcov->m_tco; - tcos.push_back( tco ); - smallestPos = qMin( smallestPos, - (int)tco->startPosition() + dtick ); - } - dtick -= smallestPos; - if( snap ) - { - dtick = dtick.toAbsoluteTact(); // round toward 0 + if( tcov == NULL ) { continue; } + tcos.push_back( tcov->m_tco ); + int index = std::distance( so.begin(), it ); + leftmost = min (leftmost, m_initialOffsets[index].getTicks() ); } + if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } + for( QVector::iterator it = tcos.begin(); it != tcos.end(); ++it ) { - ( *it )->movePosition( ( *it )->startPosition() + dtick ); + int index = std::distance( tcos.begin(), it ); + //( *it )->movePosition( ( *it )->startPosition() + dtick ); + ( *it )->movePosition( newPos + m_initialOffsets[index] ); } } else if( m_action == Resize || m_action == ResizeLeft ) @@ -1116,7 +1124,25 @@ float TrackContentObjectView::pixelsPerTact() +void TrackContentObjectView::setInitialOffsets() +{ + QVector so = m_trackView->trackContainerView()->selectedObjects(); + QVector offsets; + for( QVector::iterator it = so.begin(); + it != so.end(); ++it ) + { + TrackContentObjectView * tcov = + dynamic_cast( *it ); + if( tcov == NULL ) + { + continue; + } + TrackContentObject * tco = tcov->m_tco; + offsets.push_back( tco->startPosition() - m_initialTCOPos ); + } + m_initialOffsets = offsets; +} /*! \brief Detect whether the mouse moved more than n pixels on screen. * * \param _me The QMouseEvent. diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index b34979ff3fc..730cced9377 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -79,7 +79,6 @@ SongEditor::SongEditor( Song * song ) : m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), m_proportionalSnap( true ), - m_snapType( ShiftMode ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -337,11 +336,6 @@ void SongEditor::toggleProportionalSnap() m_proportionalSnap = !m_proportionalSnap; } -void SongEditor::setSnapMode( int state ) -{ - m_snapType = static_cast( state ); -} - @@ -788,21 +782,10 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_setProportionalSnapAction->setChecked(true); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); - NStateButton * m_snapTypeButton = new NStateButton( m_toolBar ); - m_snapTypeButton->addState( embed::getIconPixmap( "back_to_start" ), - tr( "Shift mode" ) ); - m_snapTypeButton->addState( embed::getIconPixmap( "back_to_zero" ), - tr( "Snap mode" ) ); - m_snapTypeButton->addState( embed::getIconPixmap( "keep_stop_position" ), - tr( "Snap & shift mode" ) ); - connect( m_snapTypeButton, SIGNAL( changedState( int ) ), m_editor, - SLOT( setSnapMode( int ) ) ); - snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); snapToolBar->addAction( m_setProportionalSnapAction ); - snapToolBar->addWidget( m_snapTypeButton ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); @@ -810,7 +793,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {660, 300}; + return {640, 300}; } From 2bef0b2050c899df74b8719ad86506f15bba2ea5 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 20:12:33 +0200 Subject: [PATCH 12/67] Apply enhanced snap to resizing --- include/SongEditor.h | 1 - src/core/Track.cpp | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 1f70bece479..8cedd56dc07 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -132,7 +132,6 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; - ComboBoxModel* m_snappingModel; bool m_proportionalSnap; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f8e7c3af2a6..3d5eec585cd 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -914,7 +914,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - newPos = max(0, static_cast(newPos)); // Don't go left of bar zero + newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). @@ -960,6 +960,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) int index = std::distance( so.begin(), it ); leftmost = min (leftmost, m_initialOffsets[index].getTicks() ); } + // Make sure the leftmost clip doesn't get moved to a negative position if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } for( QVector::iterator it = tcos.begin(); @@ -975,10 +976,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( m_action == Resize ) { MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); - if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) - { - t = qMax( MidiTime::ticksPerTact(), t.quantize( gui->songEditor()->m_editor->getSnapSize() ) ); + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position + MidiTime endPos = m_tco->startPosition() + t; + endPos = endPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + t = qMax( 1, endPos - m_tco->startPosition() ); + } + else + { // Otherwise, quantize resize amount + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + t = qMax( MidiTime::ticksPerTact() * snapSize , t.quantize( snapSize ) ); } + m_tco->changeLength( t ); } else @@ -992,13 +1006,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_trackView->trackContainerView()->currentPosition()+ static_cast( x * MidiTime::ticksPerTact() / ppt ) ); - if( ! ( me->modifiers() & Qt::ControlModifier ) - && me->button() == Qt::NoButton ) + if( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if( me->modifiers() & Qt::ShiftModifier ) { t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } + else + { + MidiTime offset = t - m_tco->startPosition(); + offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + t = m_tco->startPosition() + offset; + } + float snapSize = gui->songEditor()->m_editor->getSnapSize(); MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() ) + if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() * snapSize ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -1137,8 +1161,7 @@ void TrackContentObjectView::setInitialOffsets() { continue; } - TrackContentObject * tco = tcov->m_tco; - offsets.push_back( tco->startPosition() - m_initialTCOPos ); + offsets.push_back( tcov->m_tco->startPosition() - m_initialTCOPos ); } m_initialOffsets = offsets; From f4d7092c731323a7101636a1a9e9bd41b3aa15f6 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 22:21:13 +0200 Subject: [PATCH 13/67] Lots of resize fixes --- include/Track.h | 2 ++ src/core/Track.cpp | 72 ++++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/include/Track.h b/include/Track.h index 3c1d3ad5d64..98da13550be 100644 --- a/include/Track.h +++ b/include/Track.h @@ -298,6 +298,7 @@ protected slots: QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; MidiTime m_initialTCOPos; + MidiTime m_initialTCOEnd; QVector m_initialOffsets; TextFloat * m_hint; @@ -318,6 +319,7 @@ protected slots: m_initialMousePos = pos; m_initialMouseGlobalPos = mapToGlobal( pos ); m_initialTCOPos = m_tco->startPosition(); + m_initialTCOEnd = m_initialTCOPos + m_tco->length(); } void setInitialOffsets(); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 3d5eec585cd..70de16ef27a 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -269,6 +269,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), m_initialTCOPos( MidiTime(0) ), + m_initialTCOEnd( MidiTime(0) ), m_initialOffsets( QVector() ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), @@ -967,7 +968,6 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) it != tcos.end(); ++it ) { int index = std::distance( tcos.begin(), it ); - //( *it )->movePosition( ( *it )->startPosition() + dtick ); ( *it )->movePosition( newPos + m_initialOffsets[index] ); } } @@ -975,25 +975,34 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { if( m_action == Resize ) { - MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + minLength = MidiTime( 1 ); + } else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position - MidiTime endPos = m_tco->startPosition() + t; - endPos = endPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - t = qMax( 1, endPos - m_tco->startPosition() ); + { // If shift is held, quantize clip's end position + MidiTime end = MidiTime( m_initialTCOPos + l ).quantize( snapSize ); + MidiTime min = m_initialTCOPos.quantize( snapSize ); + if ( min < m_initialTCOPos ) + { min += MidiTime( MidiTime::ticksPerTact() * snapSize ); } + l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); } else - { // Otherwise, quantize resize amount - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - t = qMax( MidiTime::ticksPerTact() * snapSize , t.quantize( snapSize ) ); + { // Otherwise, resize in fixed increments + MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; + MidiTime offset = MidiTime( l - initialLength ).quantize( snapSize ); + MidiTime min = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + l = qMax( min, initialLength + offset); } - - m_tco->changeLength( t ); + l = qMax( minLength, l ); + m_tco->changeLength( l ); } else { @@ -1006,23 +1015,33 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_trackView->trackContainerView()->currentPosition()+ static_cast( x * MidiTime::ticksPerTact() / ppt ) ); + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} - else if( me->modifiers() & Qt::ShiftModifier ) + || (me->modifiers() & Qt::AltModifier) ) { - t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); + minLength = MidiTime( 1 ); + } + else if( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize clip's start position + MidiTime max = m_initialTCOEnd.quantize( snapSize ); + if ( max > m_initialTCOEnd ) + { max -= MidiTime( 1, 0 ) * snapSize; } + t = qMin( max, t.quantize( snapSize ) ); } else - { - MidiTime offset = t - m_tco->startPosition(); - offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - t = m_tco->startPosition() + offset; + { // Otherwise, resize in fixed increments + MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; + MidiTime minLength = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + MidiTime offset = MidiTime(t - m_initialTCOPos).quantize( snapSize ); + t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); } - float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() * snapSize ) + if( m_tco->length() + ( oldPos - t ) >= minLength ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -1136,7 +1155,6 @@ void TrackContentObjectView::contextMenuEvent( QContextMenuEvent * cme ) - /*! \brief How many pixels a tact (bar) takes for this trackContentObjectView. * * \return the number of pixels per tact (bar). @@ -1147,7 +1165,7 @@ float TrackContentObjectView::pixelsPerTact() } - +/*! \brief Save the offsets between all selected tracks and a clicked track */ void TrackContentObjectView::setInitialOffsets() { QVector so = m_trackView->trackContainerView()->selectedObjects(); @@ -1166,6 +1184,10 @@ void TrackContentObjectView::setInitialOffsets() m_initialOffsets = offsets; } + + + + /*! \brief Detect whether the mouse moved more than n pixels on screen. * * \param _me The QMouseEvent. From 07eabc7b5d4b9b2957b597c59eb5bc3a1e746a35 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 25 May 2019 12:20:45 +0200 Subject: [PATCH 14/67] Preserve latest offset instead of initial offset --- src/core/Track.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 70de16ef27a..2c27928c5da 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -904,8 +904,12 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); @@ -934,8 +938,12 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); @@ -977,6 +985,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); + //When snapping, avoid making the new TCO tiny MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize @@ -984,7 +993,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { + //If the user manually makes the TCO tiny, we ĺet them minLength = MidiTime( 1 ); + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position @@ -1016,6 +1029,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) static_cast( x * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); + //When snapping, avoid making the new TCO tiny MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize @@ -1023,7 +1037,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { + //If the user manually makes the TCO tiny, we ĺet them minLength = MidiTime( 1 ); + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); } else if( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's start position From 56b350f934f0eb71aa682959990a84bc06223548 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 25 May 2019 12:32:19 +0200 Subject: [PATCH 15/67] Refactoring --- include/Track.h | 2 +- src/core/Track.cpp | 79 ++++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/include/Track.h b/include/Track.h index 98da13550be..b00c5024896 100644 --- a/include/Track.h +++ b/include/Track.h @@ -324,7 +324,7 @@ protected slots: void setInitialOffsets(); bool mouseMovedDistance( QMouseEvent * me, int distance ); - + MidiTime draggedTCOPos( QMouseEvent * me ); } ; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 2c27928c5da..3ccde57f174 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -897,27 +897,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; - MidiTime offset = newPos - m_initialTCOPos; - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping - setInitialPos( m_initialMousePos ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - else - { // Otherwise, quantize moved distance (preserves user offsets) - newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } + MidiTime newPos = draggedTCOPos( me ); newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero m_tco->movePosition( newPos ); @@ -931,27 +911,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) else if( m_action == MoveSelection ) { // 1: Find the position we want to move the grabbed TCO to - // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; - MidiTime offset = newPos - m_initialTCOPos; - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping - setInitialPos( m_initialMousePos ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - else - { // Otherwise, quantize moved distance (preserves user offsets) - newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } + MidiTime newPos = draggedTCOPos( me ); // 2: Handle moving the other selected TCOs the same distance QVector so = @@ -1220,6 +1180,41 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance +/*! \bried Calculate the new position of a dragged TCO from a mouse event + * + * + * \param me The QMouseEvent + */ +MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) +{ + //Pixels per tact + const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + return newPos; +} + + + // =========================================================================== // trackContentWidget From 54cc5820b66abcd00df01c92ed85967079d27a02 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 27 May 2019 15:29:59 +0200 Subject: [PATCH 16/67] Typo fix 1 --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 730cced9377..dc48c6798b9 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -777,7 +777,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setToolTip(tr("Clip snapping")); m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), - tr("Toggle roportional snap on/off"), this); + tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(true); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); From 7fda4faf7eaf547617ecf76c17a0c9e52190edc0 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 27 May 2019 15:30:30 +0200 Subject: [PATCH 17/67] Typo fix 2 --- src/core/Track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 3ccde57f174..348c23d446c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1180,7 +1180,7 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance -/*! \bried Calculate the new position of a dragged TCO from a mouse event +/*! \brief Calculate the new position of a dragged TCO from a mouse event * * * \param me The QMouseEvent From 32a88a453aa5e3cc665360dbbe6f8416684fef8d Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 29 May 2019 10:58:52 +0200 Subject: [PATCH 18/67] Fix offset when scrolled --- src/core/Track.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 348c23d446c..0bca31041b3 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1190,8 +1190,9 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) //Pixels per tact const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + //const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); //Always starts on bar 1 + MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton From f1ab886da7a606951cc56861612cc0207ba6261d Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 29 May 2019 11:04:53 +0200 Subject: [PATCH 19/67] Clean up --- src/core/Track.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 0bca31041b3..278b505f930 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1189,9 +1189,8 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) { //Pixels per tact const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); - // The pixel position of the mouse, adjusted for where the clip was grabbed - //const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); //Always starts on bar 1 + // The pixel distance that the mouse has moved + const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize From 1e5b75d62281f5a519530dbd550a2a3f236f8d06 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 17:24:34 +0200 Subject: [PATCH 20/67] BaraMGB's suggestions from code review Except the comment positioning, holding out for a response on that. --- src/core/Track.cpp | 1 - src/gui/editors/SongEditor.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 278b505f930..710cb18eb48 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include "AutomationPattern.h" diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index dc48c6798b9..7ee18b7eaf5 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include "AutomatableSlider.h" #include "ComboBox.h" @@ -283,7 +282,8 @@ float SongEditor::getSnapSize() const{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; // If proportional snap is on, we snap to finer values when zoomed in - if (m_proportionalSnap){ + if (m_proportionalSnap) + { val = val - m_zoomingModel->value() + 3; } val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. From 1698dd5e0b3891e755b641d149e9c7eb059cd4f4 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 17:29:41 +0200 Subject: [PATCH 21/67] More code review --- src/core/Track.cpp | 3 ++- src/gui/editors/SongEditor.cpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 710cb18eb48..de3cac89645 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -898,7 +898,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { MidiTime newPos = draggedTCOPos( me ); - newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero + // Don't go left of bar zero + newPos = max( 0, newPos.getTicks() ); m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 7ee18b7eaf5..e727271c92e 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -244,14 +244,18 @@ SongEditor::SongEditor( Song * song ) : this, SLOT( zoomingChanged() ) ); //Set up snapping model, 2^i - for ( int i = 3; i >= -4; i-- ){ - if ( i > 0 ){ + for ( int i = 3; i >= -4; i-- ) + { + if ( i > 0 ) + { m_snappingModel->addItem( QString( "%1 Bars").arg( 1 << i ) ); } - else if ( i == 0 ){ + else if ( i == 0 ) + { m_snappingModel->addItem( "1 Bar" ); } - else { + else + { m_snappingModel->addItem( QString( "1/%1 Bar" ).arg( 1 << (-i) ) ); } } From d51b6335266bf2fedebb2ac8c64639178dc2ebf9 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 18:17:34 +0200 Subject: [PATCH 22/67] Proportional Snap Icon (classic) --- data/themes/classic/proportional_snap.png | Bin 0 -> 263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/classic/proportional_snap.png diff --git a/data/themes/classic/proportional_snap.png b/data/themes/classic/proportional_snap.png new file mode 100644 index 0000000000000000000000000000000000000000..66a0bb0493411d97d9a3e3b22cd779afeb0d89f2 GIT binary patch literal 263 zcmV+i0r>ujP)w8hB+L*W8jWMdbMaYZ01 Date: Sun, 2 Jun 2019 18:17:57 +0200 Subject: [PATCH 23/67] Proportional Snap Icon (default) --- data/themes/default/proportional_snap.png | Bin 0 -> 263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/default/proportional_snap.png diff --git a/data/themes/default/proportional_snap.png b/data/themes/default/proportional_snap.png new file mode 100644 index 0000000000000000000000000000000000000000..66a0bb0493411d97d9a3e3b22cd779afeb0d89f2 GIT binary patch literal 263 zcmV+i0r>ujP)w8hB+L*W8jWMdbMaYZ01 Date: Sun, 2 Jun 2019 18:19:48 +0200 Subject: [PATCH 24/67] Update proportional snap pixmap --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index e727271c92e..ea6e0f57356 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -780,7 +780,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), + m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(true); From 80ba55b1c93b7701fdd642c741684c0d8e544458 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 20:03:56 +0200 Subject: [PATCH 25/67] Proportional snap off by default --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index ea6e0f57356..7d84957a27b 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -783,7 +783,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); - m_setProportionalSnapAction->setChecked(true); + m_setProportionalSnapAction->setChecked(false); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); snapToolBar->addWidget( snap_lbl ); From 578bd099fa3ee604e2b75b31a3825f75f171e1d2 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:47:00 +0200 Subject: [PATCH 26/67] Display snap level when proportional snap enabled --- include/SongEditor.h | 6 +++- src/gui/editors/SongEditor.cpp | 58 +++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 8cedd56dc07..8a02d56919a 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -73,7 +73,9 @@ class SongEditor : public TrackContainerView void loadSettings( const QDomElement& element ); ComboBoxModel *zoomingModel() const; + ComboBoxModel *snappingModel() const; float getSnapSize() const; + QString getSnapSizeString() const; public slots: void scrolled( int new_pos ); @@ -145,7 +147,6 @@ private slots: EditMode m_ctrlMode; // mode they were in before they hit ctrl friend class SongEditorWindow; - } ; @@ -174,6 +175,8 @@ protected slots: void lostFocus(); void adjustUiAfterProjectLoad(); + void updateSnapLabel(); + signals: void playTriggered(); void resized(); @@ -194,6 +197,7 @@ protected slots: ComboBox * m_zoomingComboBox; ComboBox * m_snappingComboBox; + QLabel* m_snapSizeLabel; }; #endif diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 7d84957a27b..f19aadca9f6 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -282,7 +282,11 @@ void SongEditor::loadSettings( const QDomElement& element ) MainWindow::restoreWidgetState(parentWidget(), element); } -float SongEditor::getSnapSize() const{ + + + +float SongEditor::getSnapSize() const +{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; // If proportional snap is on, we snap to finer values when zoomed in @@ -300,6 +304,24 @@ float SongEditor::getSnapSize() const{ } } +QString SongEditor::getSnapSizeString() const +{ + int val = -m_snappingModel->value() + 3; + val = val - m_zoomingModel->value() + 3; + val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. + + if ( val >= 0 ){ + int bars = 1 << val; + return QString( "%1 Bar" ).arg(bars); + } + else { + int div = ( 1 << -val ); + return QString( "1/%1 Bar" ).arg(div); + } +} + + + void SongEditor::setHighQuality( bool hq ) { @@ -695,10 +717,19 @@ ComboBoxModel *SongEditor::zoomingModel() const +ComboBoxModel *SongEditor::snappingModel() const +{ + return m_snappingModel; +} + + + + SongEditorWindow::SongEditorWindow(Song* song) : Editor(Engine::mixer()->audioDev()->supportsCapture(), false), m_editor(new SongEditor(song)), - m_crtlAction( NULL ) + m_crtlAction( NULL ), + m_snapSizeLabel( new QLabel( m_toolBar ) ) { setWindowTitle( tr( "Song-Editor" ) ); setWindowIcon( embed::getIconPixmap( "songeditor" ) ); @@ -766,6 +797,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_zoomingComboBox->move( 580, 4 ); m_zoomingComboBox->setModel(m_editor->m_zoomingModel); m_zoomingComboBox->setToolTip(tr("Horizontal zooming")); + connect(m_editor->zoomingModel(), SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); @@ -778,26 +810,44 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox = new ComboBox( m_toolBar ); m_snappingComboBox->setFixedSize( 80, 22 ); m_snappingComboBox->setModel(m_editor->m_snappingModel); - m_snappingComboBox->setToolTip(tr("Clip snapping")); + m_snappingComboBox->setToolTip(tr("Clip snapping size")); + connect(m_editor->snappingModel(), SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(false); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); + connect(m_setProportionalSnapAction, SIGNAL(triggered()), this, SLOT(updateSnapLabel()) ); snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); snapToolBar->addAction( m_setProportionalSnapAction ); + snapToolBar->addSeparator(); + snapToolBar->addWidget( m_snapSizeLabel ); + connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); } QSize SongEditorWindow::sizeHint() const { - return {640, 300}; + return {720, 300}; +} + +void SongEditorWindow::updateSnapLabel(){ + if (m_setProportionalSnapAction->isChecked()) + { + m_snapSizeLabel->setText(QString("Snap: ") + m_editor->getSnapSizeString()); + m_snappingComboBox->setToolTip(tr("Base snapping size")); + } + else + { + m_snappingComboBox->setToolTip(tr("Clip snapping size")); + m_snapSizeLabel->clear(); + } } From 73f5ce116a5214c353d81ee43d77f00cff879cf1 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:48:49 +0200 Subject: [PATCH 27/67] Make proportional snap false at initialization --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index f19aadca9f6..2bf29dbbba7 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -77,7 +77,7 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), - m_proportionalSnap( true ), + m_proportionalSnap( false ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) From d489763880985a28871445228fea4813e5da1b08 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:53:26 +0200 Subject: [PATCH 28/67] Plurals in snap size label --- src/gui/editors/SongEditor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 2bf29dbbba7..4a7fadc4ea9 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -312,7 +312,11 @@ QString SongEditor::getSnapSizeString() const if ( val >= 0 ){ int bars = 1 << val; - return QString( "%1 Bar" ).arg(bars); + if ( bars == 1 ) { return QString("1 Bar"); + else + { + QString( "%1 Bars" ).arg(bars); + } } else { int div = ( 1 << -val ); From d51d8b4063bab031c5f643e9ad1f979eb4087188 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 23:02:54 +0200 Subject: [PATCH 29/67] Add missing "return" --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 4a7fadc4ea9..6ed090a74b1 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -315,7 +315,7 @@ QString SongEditor::getSnapSizeString() const if ( bars == 1 ) { return QString("1 Bar"); else { - QString( "%1 Bars" ).arg(bars); + return QString( "%1 Bars" ).arg(bars); } } else { From 9106dc6e715815a97d6058b6308b7ca7a82556de Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 11 Jun 2019 10:08:56 +0200 Subject: [PATCH 30/67] Update src/gui/editors/SongEditor.cpp Co-Authored-By: Hyunjin Song --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 6ed090a74b1..6e23fcdbef7 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -312,7 +312,7 @@ QString SongEditor::getSnapSizeString() const if ( val >= 0 ){ int bars = 1 << val; - if ( bars == 1 ) { return QString("1 Bar"); + if ( bars == 1 ) { return QString("1 Bar"); } else { return QString( "%1 Bars" ).arg(bars); From 34b32bfa9a4e8d9da1a300705724a588ad18cb50 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 22 Jun 2019 15:53:32 +0200 Subject: [PATCH 31/67] Better resize limits --- src/core/Track.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index de3cac89645..c81f19fd66c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -943,38 +943,39 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { if( m_action == Resize ) { - MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + MidiTime l = static_cast( me->x() * MidiTime::ticksPerTact() / ppt ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); - //When snapping, avoid making the new TCO tiny - MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // Length in ticks of one snap increment + MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { - //If the user manually makes the TCO tiny, we ĺet them - minLength = MidiTime( 1 ); // We want to preserve this adjusted offset, // even if the user switches to snapping setInitialPos( m_initialMousePos ); + // Don't resize to less than 1 tick + l = qMax( 1, l ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position MidiTime end = MidiTime( m_initialTCOPos + l ).quantize( snapSize ); + // The end position has to be after the clip's start MidiTime min = m_initialTCOPos.quantize( snapSize ); - if ( min < m_initialTCOPos ) - { min += MidiTime( MidiTime::ticksPerTact() * snapSize ); } + if ( min <= m_initialTCOPos ) min += snapLength; l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); } else { // Otherwise, resize in fixed increments MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; MidiTime offset = MidiTime( l - initialLength ).quantize( snapSize ); - MidiTime min = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + // Don't resize to less than 1 tick + MidiTime min = MidiTime( initialLength % snapLength ); + if (min < 1) min += snapLength; l = qMax( min, initialLength + offset); } - l = qMax( minLength, l ); m_tco->changeLength( l ); } else @@ -989,37 +990,39 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) static_cast( x * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); - //When snapping, avoid making the new TCO tiny - MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // Length in ticks of one snap increment + MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { - //If the user manually makes the TCO tiny, we ĺet them - minLength = MidiTime( 1 ); // We want to preserve this adjusted offset, // even if the user switches to snapping setInitialPos( m_initialMousePos ); + //Don't resize to less than 1 tick + t = qMin( m_initialTCOEnd - 1, t); } else if( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's start position + // Don't let the start position move past the end position MidiTime max = m_initialTCOEnd.quantize( snapSize ); - if ( max > m_initialTCOEnd ) - { max -= MidiTime( 1, 0 ) * snapSize; } + if ( max >= m_initialTCOEnd ) max -= snapLength; t = qMin( max, t.quantize( snapSize ) ); } else { // Otherwise, resize in fixed increments + // Don't resize to less than 1 tick MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; - MidiTime minLength = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + MidiTime minLength = MidiTime( initialLength % snapLength ); + if (minLength < 1) minLength += snapLength; MidiTime offset = MidiTime(t - m_initialTCOPos).quantize( snapSize ); t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); } MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= minLength ) + if( m_tco->length() + ( oldPos - t ) >= 1 ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); From 0a757d36346150673ac1bc4f0c30764856a89b87 Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 26 Jun 2019 19:16:19 +0200 Subject: [PATCH 32/67] Consolidation attempt --- src/core/Track.cpp | 47 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index c81f19fd66c..6fb93245191 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -941,23 +941,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == Resize || m_action == ResizeLeft ) { + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + const bool unquantized = (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier); + const float snapSize = gui->songEditor()->m_editor->getSnapSize(); + // Length in ticks of one snap increment + const MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); + if( m_action == Resize ) { + // The clip's new length MidiTime l = static_cast( me->x() * MidiTime::ticksPerTact() / ppt ); - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - // Length in ticks of one snap increment - MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); - - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping + + if ( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later setInitialPos( m_initialMousePos ); // Don't resize to less than 1 tick - l = qMax( 1, l ); + m_tco->changeLength( qMax( 1, l ) ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position @@ -965,7 +965,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // The end position has to be after the clip's start MidiTime min = m_initialTCOPos.quantize( snapSize ); if ( min <= m_initialTCOPos ) min += snapLength; - l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); + m_tco->changeLength( qMax(min - m_initialTCOPos, end - m_initialTCOPos) ); } else { // Otherwise, resize in fixed increments @@ -974,9 +974,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // Don't resize to less than 1 tick MidiTime min = MidiTime( initialLength % snapLength ); if (min < 1) min += snapLength; - l = qMax( min, initialLength + offset); + m_tco->changeLength( qMax( min, initialLength + offset) ); } - m_tco->changeLength( l ); } else { @@ -987,19 +986,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime t = qMax( 0, (int) m_trackView->trackContainerView()->currentPosition()+ - static_cast( x * MidiTime::ticksPerTact() / - ppt ) ); - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - // Length in ticks of one snap increment - MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); - - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping + static_cast( x * MidiTime::ticksPerTact() / ppt ) ); + + if( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later setInitialPos( m_initialMousePos ); //Don't resize to less than 1 tick t = qMin( m_initialTCOEnd - 1, t); From 4736c3831c4a5f29419038a731bded899a7d2af2 Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 12 Jul 2019 21:48:41 +0200 Subject: [PATCH 33/67] Also snap end position in shift mode --- src/core/Track.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 6fb93245191..fe66ab4a5e5 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1198,7 +1198,15 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + // or end position, whichever is closest to the actual position + MidiTime startQ = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + // Find start position that gives snapped clip end position + MidiTime endQ = ( newPos + m_tco->length() ); + endQ = endQ.quantize( gui->songEditor()->m_editor->getSnapSize() ); + endQ = endQ - m_tco->length(); + // Select the position closest to actual position + if ( abs(newPos - startQ) < abs(newPos - endQ) ) newPos = startQ; + else newPos = endQ; } else { // Otherwise, quantize moved distance (preserves user offsets) From d87cf8f1fa24890f48ee9ea1ec68534bfd30ec6d Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 15 May 2019 19:43:22 +0200 Subject: [PATCH 34/67] Mostly working --- include/MidiTime.h | 3 +-- include/SongEditor.h | 3 +++ src/core/Track.cpp | 8 +++---- src/core/midi/MidiTime.cpp | 20 +++++++++++------ src/gui/TimeLineWidget.cpp | 6 ++--- src/gui/editors/SongEditor.cpp | 40 +++++++++++++++++++++++++++++++--- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/include/MidiTime.h b/include/MidiTime.h index 7aaacf96344..0e8015e04cf 100644 --- a/include/MidiTime.h +++ b/include/MidiTime.h @@ -63,7 +63,7 @@ class LMMS_EXPORT MidiTime MidiTime( const tact_t tact, const tick_t ticks ); MidiTime( const tick_t ticks = 0 ); - MidiTime toNearestTact() const; + MidiTime quantize(float) const; MidiTime toAbsoluteTact() const; MidiTime& operator+=( const MidiTime& time ); @@ -110,4 +110,3 @@ class LMMS_EXPORT MidiTime #endif - diff --git a/include/SongEditor.h b/include/SongEditor.h index f9b6aad1b56..02bc523f295 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -73,6 +73,7 @@ class SongEditor : public TrackContainerView void loadSettings( const QDomElement& element ); ComboBoxModel *zoomingModel() const; + float getSnapSize() const; public slots: void scrolled( int new_pos ); @@ -130,6 +131,7 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; + ComboBoxModel* m_snappingModel; static const QVector m_zoomLevels; @@ -188,6 +190,7 @@ protected slots: QAction* m_crtlAction; ComboBox * m_zoomingComboBox; + ComboBox * m_snappingComboBox; }; #endif diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 64c17c9e8ec..5f8c84f9431 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -897,7 +897,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.toNearestTact(); + t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -920,7 +920,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime::ticksPerTact() / ppt ) ); if( snap ) { - dtick = dtick.toNearestTact(); + dtick = dtick.quantize( gui->songEditor()->m_editor->getSnapSize() ); } // find out smallest position of all selected objects for not // moving an object before zero @@ -956,7 +956,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = qMax( MidiTime::ticksPerTact(), t.toNearestTact() ); + t = qMax( MidiTime::ticksPerTact(), t.quantize( gui->songEditor()->m_editor->getSnapSize() ) ); } m_tco->changeLength( t ); } @@ -974,7 +974,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.toNearestTact(); + t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } MidiTime oldPos = m_tco->startPosition(); if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() ) diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index b4607aee9c3..7dbbf19ebaf 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -63,13 +63,19 @@ MidiTime::MidiTime( const tick_t ticks ) : { } -MidiTime MidiTime::toNearestTact() const -{ - if( m_ticks % s_ticksPerTact >= s_ticksPerTact/2 ) - { - return ( getTact() + 1 ) * s_ticksPerTact; - } - return getTact() * s_ticksPerTact; +MidiTime MidiTime::quantize(float bars) const +{ + //float bars = 0.5; + //The intervals we should snap to, our new position should be a factor of this + int interval = s_ticksPerTact * bars; + //The lower position we could snap to + int lowPos = m_ticks / interval; + //Offset from the lower position + int offset = m_ticks % interval; + //1 if we should snap up, 0 if we shouldn't + int snapUp = offset / (interval / 2); + + return (lowPos + snapUp) * interval; } diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 7c7f48c4ef3..87e513e7242 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -2,7 +2,7 @@ * TimeLineWidget.cpp - class timeLine, representing a time-line with position marker * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of LMMS - https://lmms.io * * This program is free software; you can redistribute it and/or @@ -384,14 +384,14 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) } else { - m_loopPos[i] = t.toNearestTact(); + m_loopPos[i] = t.quantize(1.0); } // Catch begin == end if( m_loopPos[0] == m_loopPos[1] ) { // Note, swap 1 and 0 below and the behavior "skips" the other // marking instead of pushing it. - if( m_action == MoveLoopBegin ) + if( m_action == MoveLoopBegin ) m_loopPos[0] -= MidiTime::ticksPerTact(); else m_loopPos[1] += MidiTime::ticksPerTact(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index b397434b102..57673a42927 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "AutomatableSlider.h" #include "ComboBox.h" @@ -76,11 +77,13 @@ SongEditor::SongEditor( Song * song ) : TrackContainerView( song ), m_song( song ), m_zoomingModel(new ComboBoxModel()), + m_snappingModel(new ComboBoxModel()), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) { m_zoomingModel->setParent(this); + m_snappingModel->setParent(this); // create time-line m_widgetWidthTotal = ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt()==1 ? @@ -230,7 +233,7 @@ SongEditor::SongEditor( Song * song ) : connect( m_song, SIGNAL( lengthChanged( int ) ), this, SLOT( updateScrollBar( int ) ) ); - // Set up zooming model + //Set up zooming model for( float const & zoomLevel : m_zoomLevels ) { m_zoomingModel->addItem( QString( "%1\%" ).arg( zoomLevel * 100 ) ); @@ -240,6 +243,20 @@ SongEditor::SongEditor( Song * song ) : connect( m_zoomingModel, SIGNAL( dataChanged() ), this, SLOT( zoomingChanged() ) ); + //Set up snapping model, 2^i + for ( int i = 3; i >= -4; i-- ){ + if ( i > 0 ){ + m_snappingModel->addItem( QString( "%1 Bars").arg( 1 << i ) ); + } + else if ( i == 0 ){ + m_snappingModel->addItem( "1 Bar" ); + } + else { + m_snappingModel->addItem( QString( "1/%1 Bar" ).arg( 1 << (-i) ) ); + } + } + m_snappingModel->setInitValue( m_snappingModel->findText( "1 Bar" ) ); + setFocusPolicy( Qt::StrongFocus ); setFocus(); } @@ -261,7 +278,15 @@ void SongEditor::loadSettings( const QDomElement& element ) MainWindow::restoreWidgetState(parentWidget(), element); } - +float SongEditor::getSnapSize() const{ + int val = -m_snappingModel->value() + 3; + if ( val >= 0 ){ + return 1 << val; + } + else { + return 1.0 / ( 1 << abs(val) ); + } +} void SongEditor::setHighQuality( bool hq ) @@ -718,7 +743,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QLabel * zoom_lbl = new QLabel( m_toolBar ); zoom_lbl->setPixmap( embed::getIconPixmap( "zoom" ) ); - // setup zooming-stuff + //Set up zooming-stuff m_zoomingComboBox = new ComboBox( m_toolBar ); m_zoomingComboBox->setFixedSize( 80, 22 ); m_zoomingComboBox->move( 580, 4 ); @@ -728,6 +753,15 @@ SongEditorWindow::SongEditorWindow(Song* song) : zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); + //Set up quantization/snapping selector + m_snappingComboBox = new ComboBox( m_toolBar ); + m_snappingComboBox->setFixedSize( 80, 22 ); + //m_snappingComboBox->move( 580 + 80 + 100, 4 ); + m_snappingComboBox->setModel(m_editor->m_snappingModel); + m_snappingComboBox->setToolTip(tr("Clip snapping")); + + zoomToolBar->addWidget( m_snappingComboBox ); + connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); } From 3602aa79fb7afc0c5557a684451def3a8cdc1df9 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:15:53 +0200 Subject: [PATCH 35/67] Simplify and fix snapping for pattern cloning --- src/core/Track.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 5f8c84f9431..5fbe5327f8b 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -524,7 +524,7 @@ void TrackContentObjectView::updatePosition() void TrackContentObjectView::dragEnterEvent( QDragEnterEvent * dee ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition().getTact(), 0 ); + MidiTime tcoPos = MidiTime( m_tco->startPosition() ); if( tcw->canPasteSelection( tcoPos, dee ) == false ) { dee->ignore(); @@ -563,7 +563,7 @@ void TrackContentObjectView::dropEvent( QDropEvent * de ) if( m_trackView->trackContainerView()->allowRubberband() == true ) { TrackContentWidget * tcw = getTrackView()->getTrackContentWidget(); - MidiTime tcoPos = MidiTime( m_tco->startPosition().getTact(), 0 ); + MidiTime tcoPos = MidiTime( m_tco->startPosition() ); if( tcw->pasteSelection( tcoPos, de ) == true ) { de->accept(); @@ -1399,6 +1399,7 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { + tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); @@ -1517,6 +1518,10 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // TODO -- Need to draw the hovericon either way, or ghost the TCOs // onto their final position. + // All patterns should be offset the same amount as the grabbed pattern + // The offset is quantized (rather than the positions) to preserve fine adjustments + int offset = MidiTime(tcoPos - grabbedTCOPos).quantize(gui->songEditor()->m_editor->getSnapSize()); + for( int i = 0; icreateTCO( pos ); tco->restoreState( tcoElement ); @@ -1562,7 +1562,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) */ void TrackContentWidget::dropEvent( QDropEvent * de ) { - MidiTime tcoPos = MidiTime( getPosition( de->pos().x() ).getTact(), 0 ); + MidiTime tcoPos = MidiTime( getPosition( de->pos().x() ) ); if( pasteSelection( tcoPos, de ) == true ) { de->accept(); From dac6c323b53c34adb14edcf31af666f8d428aa3a Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:22:06 +0200 Subject: [PATCH 36/67] Add icon --- src/core/Track.cpp | 2 +- src/gui/editors/SongEditor.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 5fbe5327f8b..b72b9fe80a8 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1532,7 +1532,7 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) Track * t = tracks.at( finalTrackIndex ); // The new position is the old position plus the offset. - MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + snappedOffset; + MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset; TrackContentObject * tco = t->createTCO( pos ); tco->restoreState( tcoElement ); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 57673a42927..e040388f105 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -753,14 +753,18 @@ SongEditorWindow::SongEditorWindow(Song* song) : zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); + DropToolBar *snapToolBar = addDropToolBarToTop(tr("Snap controls")); + QLabel * snap_lbl = new QLabel( m_toolBar ); + snap_lbl->setPixmap( embed::getIconPixmap( "quantize" ) ); + //Set up quantization/snapping selector m_snappingComboBox = new ComboBox( m_toolBar ); m_snappingComboBox->setFixedSize( 80, 22 ); - //m_snappingComboBox->move( 580 + 80 + 100, 4 ); m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - zoomToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addWidget( snap_lbl ); + snapToolBar->addWidget( m_snappingComboBox ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); From fbe4371561ca787a9aac5f00293b24a99b3ca2f8 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 17:46:23 +0200 Subject: [PATCH 37/67] Adaptive Snap --- include/SongEditor.h | 3 +++ src/gui/editors/SongEditor.cpp | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 02bc523f295..89ed4e7ce89 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -81,6 +81,7 @@ public slots: void setEditMode( EditMode mode ); void setEditModeDraw(); void setEditModeSelect(); + void toggleAdaptiveSnap(); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -132,6 +133,7 @@ private slots: ComboBoxModel* m_zoomingModel; ComboBoxModel* m_snappingModel; + bool m_adaptiveSnap; static const QVector m_zoomLevels; @@ -183,6 +185,7 @@ protected slots: QAction* m_addBBTrackAction; QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; + QAction* m_setAdaptiveSnapAction; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index e040388f105..2a5b9e982ee 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -78,6 +78,7 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), + m_adaptiveSnap( true ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -280,11 +281,15 @@ void SongEditor::loadSettings( const QDomElement& element ) float SongEditor::getSnapSize() const{ int val = -m_snappingModel->value() + 3; + if (m_adaptiveSnap){ + val = val - m_zoomingModel->value() + 3; + } + if ( val >= 0 ){ return 1 << val; } else { - return 1.0 / ( 1 << abs(val) ); + return 1.0 / ( 1 << -val ); } } @@ -323,6 +328,11 @@ void SongEditor::setEditModeSelect() setEditMode(SelectMode); } +void SongEditor::toggleAdaptiveSnap() +{ + m_adaptiveSnap = !m_adaptiveSnap; +} + @@ -763,8 +773,16 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); + m_setAdaptiveSnapAction = new QAction(embed::getIconPixmap("add_automation"), + tr("Enable adaptive snap"), this); + m_setAdaptiveSnapAction->setCheckable(true); + m_setAdaptiveSnapAction->setChecked(true); + + connect(m_setAdaptiveSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleAdaptiveSnap())); + snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addAction( m_setAdaptiveSnapAction ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); From 45f78b6e7ecc27bcb402ef9ab096b8229144a72d Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 18:04:06 +0200 Subject: [PATCH 38/67] Fix potential crash by capping snap fineness. Add space between adaptive snap dropdown and button --- src/gui/editors/SongEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 2a5b9e982ee..1e1bc561190 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -280,10 +280,13 @@ void SongEditor::loadSettings( const QDomElement& element ) } float SongEditor::getSnapSize() const{ + // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; + // If adaptive snap is on, we snap to finer values when zoomed in if (m_adaptiveSnap){ val = val - m_zoomingModel->value() + 3; } + val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. if ( val >= 0 ){ return 1 << val; @@ -782,6 +785,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); + snapToolBar->addSeparator(); snapToolBar->addAction( m_setAdaptiveSnapAction ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); From 2ad7401c32874b830b40977e3feb5b6bef27e849 Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 18:53:08 +0200 Subject: [PATCH 39/67] Fix cloning of short patterns --- src/core/Track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index b72b9fe80a8..87bfe25b5e1 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1399,7 +1399,7 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { - tcoPos = MidiTime(tcoPos.getTact(), 0); + //tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); From b74e1fe53230999aed1217f74ad948fb27987fce Mon Sep 17 00:00:00 2001 From: Spekular Date: Thu, 16 May 2019 19:38:03 +0200 Subject: [PATCH 40/67] Widen song editor's default size, remove unused lines --- src/core/Track.cpp | 2 -- src/gui/editors/SongEditor.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 87bfe25b5e1..0eb12269885 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1399,7 +1399,6 @@ void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee ) */ bool TrackContentWidget::canPasteSelection( MidiTime tcoPos, const QDropEvent* de ) { - //tcoPos = MidiTime(tcoPos.getTact(), 0); const QMimeData * mimeData = de->mimeData(); Track * t = getTrack(); @@ -1497,7 +1496,6 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) int initialTrackIndex = tiAttr.value().toInt(); QDomAttr tcoPosAttr = metadata.attributeNode( "grabbedTCOPos" ); MidiTime grabbedTCOPos = tcoPosAttr.value().toInt(); - MidiTime grabbedTCOTact = MidiTime( grabbedTCOPos.getTact(), 0 ); // Snap the mouse position to the beginning of the dropped tact, in ticks const TrackContainer::TrackList tracks = getTrack()->trackContainer()->tracks(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 1e1bc561190..16dd6c233ec 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -794,7 +794,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {600, 300}; + return {640, 300}; } From eda9b48364f4427e4f50ba9ff7e9d0bbe5173d5f Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 17 May 2019 20:26:13 +0200 Subject: [PATCH 41/67] Preserve offsets! --- include/Track.h | 8 ++++---- src/core/Track.cpp | 18 +++++++++++------- src/core/midi/MidiTime.cpp | 1 - 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/Track.h b/include/Track.h index 1267d2ef742..31e91be1acb 100644 --- a/include/Track.h +++ b/include/Track.h @@ -236,7 +236,7 @@ class TrackContentObjectView : public selectableObject, public ModelView // access needsUpdate member variable bool needsUpdate(); void setNeedsUpdate( bool b ); - + public slots: virtual bool close(); void cut(); @@ -564,13 +564,13 @@ class LMMS_EXPORT Track : public Model, public JournallingObject using Model::dataChanged; - inline int getHeight() + inline int getHeight() { return m_height >= MINIMAL_TRACK_HEIGHT - ? m_height + ? m_height : DEFAULT_TRACK_HEIGHT; } - inline void setHeight( int height ) + inline void setHeight( int height ) { m_height = height; } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 0eb12269885..90885eccf7a 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -889,17 +889,18 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); - MidiTime t = qMax( 0, (int) - m_trackView->trackContainerView()->currentPosition()+ - static_cast( x * MidiTime::ticksPerTact() / - ppt ) ); + const int mousePixPos = mapToParent( me->pos() ).x(); + MidiTime mousePos = static_cast( mousePixPos * MidiTime::ticksPerTact() / ppt ); + MidiTime mouseStart = static_cast( mapToParent(m_initialMousePos).x() * MidiTime::ticksPerTact() / ppt ); + MidiTime offset = mousePos - mouseStart; + if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); + offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - m_tco->movePosition( t ); + + m_tco->movePosition( m_tco->startPosition() + offset ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). arg( m_tco->startPosition().getTact() + 1 ). @@ -1531,6 +1532,9 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // The new position is the old position plus the offset. MidiTime pos = tcoElement.attributeNode( "pos" ).value().toInt() + offset; + // If we land on ourselves, offset by one snap + MidiTime shift = MidiTime::ticksPerTact() * gui->songEditor()->m_editor->getSnapSize(); + if (offset == 0) { pos += shift; } TrackContentObject * tco = t->createTCO( pos ); tco->restoreState( tcoElement ); diff --git a/src/core/midi/MidiTime.cpp b/src/core/midi/MidiTime.cpp index 7dbbf19ebaf..82ed642ba78 100644 --- a/src/core/midi/MidiTime.cpp +++ b/src/core/midi/MidiTime.cpp @@ -65,7 +65,6 @@ MidiTime::MidiTime( const tick_t ticks ) : MidiTime MidiTime::quantize(float bars) const { - //float bars = 0.5; //The intervals we should snap to, our new position should be a factor of this int interval = s_ticksPerTact * bars; //The lower position we could snap to From 89dfcba7ae698e44f0177e9e57ffdf3bfb79453b Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 17 May 2019 20:33:49 +0200 Subject: [PATCH 42/67] Clamp position to be non-negative --- src/core/Track.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 90885eccf7a..59fa1f57e77 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -900,7 +900,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - m_tco->movePosition( m_tco->startPosition() + offset ); + MidiTime newPos = max(0, m_tco->startPosition() + offset); + m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). arg( m_tco->startPosition().getTact() + 1 ). From b3094f4bf5764f6fb0e8a1d072b831c0dcc913d1 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 18 May 2019 11:54:04 +0200 Subject: [PATCH 43/67] Snap modes for single clip move --- include/SongEditor.h | 23 ++++++++++++++++--- include/Track.h | 4 +++- src/core/Track.cpp | 35 ++++++++++++++++++---------- src/gui/editors/SongEditor.cpp | 42 +++++++++++++++++++++++----------- 4 files changed, 75 insertions(+), 29 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 89ed4e7ce89..e52f40fb3f9 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -32,6 +32,7 @@ #include "ActionGroup.h" #include "Editor.h" #include "TrackContainerView.h" +#include "NStateButton.h" class QLabel; class QScrollBar; @@ -66,6 +67,13 @@ class SongEditor : public TrackContainerView SelectMode }; + enum SnapType + { + ShiftMode, + SnapMode, + BothMode + }; + SongEditor( Song * song ); ~SongEditor(); @@ -74,6 +82,10 @@ class SongEditor : public TrackContainerView ComboBoxModel *zoomingModel() const; float getSnapSize() const; + SnapType snapType() const + { + return m_snapType; + } public slots: void scrolled( int new_pos ); @@ -81,7 +93,8 @@ public slots: void setEditMode( EditMode mode ); void setEditModeDraw(); void setEditModeSelect(); - void toggleAdaptiveSnap(); + void toggleProportionalSnap(); + void setSnapMode( int ); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -132,8 +145,11 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; + ComboBoxModel* m_snappingModel; - bool m_adaptiveSnap; + bool m_proportionalSnap; + + SnapType m_snapType; static const QVector m_zoomLevels; @@ -185,7 +201,8 @@ protected slots: QAction* m_addBBTrackAction; QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; - QAction* m_setAdaptiveSnapAction; + QAction* m_setProportionalSnapAction; + NStateButton* m_snapTypeButton; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/include/Track.h b/include/Track.h index 31e91be1acb..e94f0ba51f1 100644 --- a/include/Track.h +++ b/include/Track.h @@ -297,6 +297,7 @@ protected slots: Actions m_action; QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; + MidiTime m_initialTCOPos; TextFloat * m_hint; @@ -311,10 +312,11 @@ protected slots: bool m_gradient; bool m_needsUpdate; - inline void setInitialMousePos( QPoint pos ) + inline void setInitialPos( QPoint pos ) { m_initialMousePos = pos; m_initialMouseGlobalPos = mapToGlobal( pos ); + m_initialTCOPos = m_tco->startPosition(); } bool mouseMovedDistance( QMouseEvent * me, int distance ); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 59fa1f57e77..f7bf227fdc0 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -267,6 +267,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_action( NoAction ), m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), + m_initialTCOPos( MidiTime(0) ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), m_mutedBackgroundColor( 0, 0, 0 ), @@ -711,7 +712,7 @@ void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & pai */ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) { - setInitialMousePos( me->pos() ); + setInitialPos( me->pos() ); if( !fixedTCOs() && me->button() == Qt::LeftButton ) { if( me->modifiers() & Qt::ControlModifier ) @@ -739,7 +740,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) // move or resize m_tco->setJournalling( false ); - setInitialMousePos( me->pos() ); + setInitialPos( me->pos() ); SampleTCO * sTco = dynamic_cast( m_tco ); if( me->x() < RESIZE_GRIP_WIDTH && sTco @@ -889,23 +890,33 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int mousePixPos = mapToParent( me->pos() ).x(); - MidiTime mousePos = static_cast( mousePixPos * MidiTime::ticksPerTact() / ppt ); - MidiTime mouseStart = static_cast( mapToParent(m_initialMousePos).x() * MidiTime::ticksPerTact() / ppt ); - MidiTime offset = mousePos - mouseStart; - + const int pixPos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = pixPos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If ctrl isn't held, we need to quantize if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) { - offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + MidiTime snapPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + MidiTime shiftPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + switch ( gui->songEditor()->m_editor->snapType() ){ + case SongEditor::SnapMode : newPos = snapPos; break; + case SongEditor::ShiftMode: newPos = shiftPos; break; + default: + if ( abs(newPos - snapPos) < abs(newPos - shiftPos) ){ + newPos = snapPos; + } + else { + newPos = shiftPos; + } + } } - - MidiTime newPos = max(0, m_tco->startPosition() + offset); + newPos = max(0, static_cast(newPos)); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). - arg( m_tco->startPosition().getTact() + 1 ). - arg( m_tco->startPosition().getTicks() % + arg( newPos.getTact() + 1 ). + arg( newPos.getTicks() % MidiTime::ticksPerTact() ) ); s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) ); } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 16dd6c233ec..b34979ff3fc 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -78,7 +78,8 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), - m_adaptiveSnap( true ), + m_proportionalSnap( true ), + m_snapType( ShiftMode ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -282,8 +283,8 @@ void SongEditor::loadSettings( const QDomElement& element ) float SongEditor::getSnapSize() const{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; - // If adaptive snap is on, we snap to finer values when zoomed in - if (m_adaptiveSnap){ + // If proportional snap is on, we snap to finer values when zoomed in + if (m_proportionalSnap){ val = val - m_zoomingModel->value() + 3; } val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. @@ -331,9 +332,14 @@ void SongEditor::setEditModeSelect() setEditMode(SelectMode); } -void SongEditor::toggleAdaptiveSnap() +void SongEditor::toggleProportionalSnap() { - m_adaptiveSnap = !m_adaptiveSnap; + m_proportionalSnap = !m_proportionalSnap; +} + +void SongEditor::setSnapMode( int state ) +{ + m_snapType = static_cast( state ); } @@ -776,17 +782,27 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - m_setAdaptiveSnapAction = new QAction(embed::getIconPixmap("add_automation"), - tr("Enable adaptive snap"), this); - m_setAdaptiveSnapAction->setCheckable(true); - m_setAdaptiveSnapAction->setChecked(true); - - connect(m_setAdaptiveSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleAdaptiveSnap())); + m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), + tr("Toggle roportional snap on/off"), this); + m_setProportionalSnapAction->setCheckable(true); + m_setProportionalSnapAction->setChecked(true); + connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); + + NStateButton * m_snapTypeButton = new NStateButton( m_toolBar ); + m_snapTypeButton->addState( embed::getIconPixmap( "back_to_start" ), + tr( "Shift mode" ) ); + m_snapTypeButton->addState( embed::getIconPixmap( "back_to_zero" ), + tr( "Snap mode" ) ); + m_snapTypeButton->addState( embed::getIconPixmap( "keep_stop_position" ), + tr( "Snap & shift mode" ) ); + connect( m_snapTypeButton, SIGNAL( changedState( int ) ), m_editor, + SLOT( setSnapMode( int ) ) ); snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); - snapToolBar->addAction( m_setAdaptiveSnapAction ); + snapToolBar->addAction( m_setProportionalSnapAction ); + snapToolBar->addWidget( m_snapTypeButton ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); @@ -794,7 +810,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {640, 300}; + return {660, 300}; } From e8a970f1d4ff927a892e765fbbeb32715c6b6fde Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 19:29:56 +0200 Subject: [PATCH 44/67] Use modifier keys instead of toggle for snap behavior, allow different snapping for selections, allow alt for fine movement --- include/SongEditor.h | 16 ----- include/Track.h | 2 + src/core/Track.cpp | 120 ++++++++++++++++++++------------- src/gui/editors/SongEditor.cpp | 19 +----- 4 files changed, 76 insertions(+), 81 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index e52f40fb3f9..1f70bece479 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -32,7 +32,6 @@ #include "ActionGroup.h" #include "Editor.h" #include "TrackContainerView.h" -#include "NStateButton.h" class QLabel; class QScrollBar; @@ -67,13 +66,6 @@ class SongEditor : public TrackContainerView SelectMode }; - enum SnapType - { - ShiftMode, - SnapMode, - BothMode - }; - SongEditor( Song * song ); ~SongEditor(); @@ -82,10 +74,6 @@ class SongEditor : public TrackContainerView ComboBoxModel *zoomingModel() const; float getSnapSize() const; - SnapType snapType() const - { - return m_snapType; - } public slots: void scrolled( int new_pos ); @@ -94,7 +82,6 @@ public slots: void setEditModeDraw(); void setEditModeSelect(); void toggleProportionalSnap(); - void setSnapMode( int ); void updatePosition( const MidiTime & t ); void updatePositionLine(); @@ -149,8 +136,6 @@ private slots: ComboBoxModel* m_snappingModel; bool m_proportionalSnap; - SnapType m_snapType; - static const QVector m_zoomLevels; bool m_scrollBack; @@ -202,7 +187,6 @@ protected slots: QAction* m_addSampleTrackAction; QAction* m_addAutomationTrackAction; QAction* m_setProportionalSnapAction; - NStateButton* m_snapTypeButton; ActionGroup * m_editModeGroup; QAction* m_drawModeAction; diff --git a/include/Track.h b/include/Track.h index e94f0ba51f1..3c1d3ad5d64 100644 --- a/include/Track.h +++ b/include/Track.h @@ -298,6 +298,7 @@ protected slots: QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; MidiTime m_initialTCOPos; + QVector m_initialOffsets; TextFloat * m_hint; @@ -318,6 +319,7 @@ protected slots: m_initialMouseGlobalPos = mapToGlobal( pos ); m_initialTCOPos = m_tco->startPosition(); } + void setInitialOffsets(); bool mouseMovedDistance( QMouseEvent * me, int distance ); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f7bf227fdc0..f8e7c3af2a6 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "AutomationPattern.h" @@ -268,6 +269,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), m_initialTCOPos( MidiTime(0) ), + m_initialOffsets( QVector() ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), m_mutedBackgroundColor( 0, 0, 0 ), @@ -713,6 +715,7 @@ void TrackContentObjectView::paintTextLabel(QString const & text, QPainter & pai void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) { setInitialPos( me->pos() ); + setInitialOffsets(); if( !fixedTCOs() && me->button() == Qt::LeftButton ) { if( me->modifiers() & Qt::ControlModifier ) @@ -726,7 +729,9 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) m_action = ToggleSelected; } } - else if( !me->modifiers() ) + else if( !me->modifiers() + || (me->modifiers() & Qt::AltModifier) + || (me->modifiers() & Qt::ShiftModifier) ) { if( isSelected() ) { @@ -741,6 +746,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) m_tco->setJournalling( false ); setInitialPos( me->pos() ); + setInitialOffsets(); SampleTCO * sTco = dynamic_cast( m_tco ); if( me->x() < RESIZE_GRIP_WIDTH && sTco @@ -890,27 +896,24 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - const int pixPos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = pixPos * MidiTime::ticksPerTact() / ppt; + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; - // If ctrl isn't held, we need to quantize - if( ! ( me->modifiers() & Qt::ControlModifier ) - && me->button() == Qt::NoButton ) - { - MidiTime snapPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - MidiTime shiftPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - switch ( gui->songEditor()->m_editor->snapType() ){ - case SongEditor::SnapMode : newPos = snapPos; break; - case SongEditor::ShiftMode: newPos = shiftPos; break; - default: - if ( abs(newPos - snapPos) < abs(newPos - shiftPos) ){ - newPos = snapPos; - } - else { - newPos = shiftPos; - } - } + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + newPos = max(0, static_cast(newPos)); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); @@ -922,44 +925,49 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == MoveSelection ) { - const int dx = me->x() - m_initialMousePos.x(); - const bool snap = !(me->modifiers() & Qt::ControlModifier) && - me->button() == Qt::NoButton; + // 1: Find the position we want to move the grabbed TCO to + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + + // 2: Handle moving the other selected TCOs the same distance QVector so = m_trackView->trackContainerView()->selectedObjects(); - QVector tcos; - int smallestPos = 0; - MidiTime dtick = MidiTime( static_cast( dx * - MidiTime::ticksPerTact() / ppt ) ); - if( snap ) - { - dtick = dtick.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - // find out smallest position of all selected objects for not - // moving an object before zero + QVector tcos; // List of selected clips + int leftmost = 0; // Leftmost clip's offset from grabbed clip + // Populate tcos, find leftmost for( QVector::iterator it = so.begin(); it != so.end(); ++it ) { TrackContentObjectView * tcov = dynamic_cast( *it ); - if( tcov == NULL ) - { - continue; - } - TrackContentObject * tco = tcov->m_tco; - tcos.push_back( tco ); - smallestPos = qMin( smallestPos, - (int)tco->startPosition() + dtick ); - } - dtick -= smallestPos; - if( snap ) - { - dtick = dtick.toAbsoluteTact(); // round toward 0 + if( tcov == NULL ) { continue; } + tcos.push_back( tcov->m_tco ); + int index = std::distance( so.begin(), it ); + leftmost = min (leftmost, m_initialOffsets[index].getTicks() ); } + if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } + for( QVector::iterator it = tcos.begin(); it != tcos.end(); ++it ) { - ( *it )->movePosition( ( *it )->startPosition() + dtick ); + int index = std::distance( tcos.begin(), it ); + //( *it )->movePosition( ( *it )->startPosition() + dtick ); + ( *it )->movePosition( newPos + m_initialOffsets[index] ); } } else if( m_action == Resize || m_action == ResizeLeft ) @@ -1116,7 +1124,25 @@ float TrackContentObjectView::pixelsPerTact() +void TrackContentObjectView::setInitialOffsets() +{ + QVector so = m_trackView->trackContainerView()->selectedObjects(); + QVector offsets; + for( QVector::iterator it = so.begin(); + it != so.end(); ++it ) + { + TrackContentObjectView * tcov = + dynamic_cast( *it ); + if( tcov == NULL ) + { + continue; + } + TrackContentObject * tco = tcov->m_tco; + offsets.push_back( tco->startPosition() - m_initialTCOPos ); + } + m_initialOffsets = offsets; +} /*! \brief Detect whether the mouse moved more than n pixels on screen. * * \param _me The QMouseEvent. diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index b34979ff3fc..730cced9377 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -79,7 +79,6 @@ SongEditor::SongEditor( Song * song ) : m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), m_proportionalSnap( true ), - m_snapType( ShiftMode ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) @@ -337,11 +336,6 @@ void SongEditor::toggleProportionalSnap() m_proportionalSnap = !m_proportionalSnap; } -void SongEditor::setSnapMode( int state ) -{ - m_snapType = static_cast( state ); -} - @@ -788,21 +782,10 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_setProportionalSnapAction->setChecked(true); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); - NStateButton * m_snapTypeButton = new NStateButton( m_toolBar ); - m_snapTypeButton->addState( embed::getIconPixmap( "back_to_start" ), - tr( "Shift mode" ) ); - m_snapTypeButton->addState( embed::getIconPixmap( "back_to_zero" ), - tr( "Snap mode" ) ); - m_snapTypeButton->addState( embed::getIconPixmap( "keep_stop_position" ), - tr( "Snap & shift mode" ) ); - connect( m_snapTypeButton, SIGNAL( changedState( int ) ), m_editor, - SLOT( setSnapMode( int ) ) ); - snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); snapToolBar->addAction( m_setProportionalSnapAction ); - snapToolBar->addWidget( m_snapTypeButton ); connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); @@ -810,7 +793,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {660, 300}; + return {640, 300}; } From c86ae7946f920bc30155fc336c2980d0f0fa94da Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 20:12:33 +0200 Subject: [PATCH 45/67] Apply enhanced snap to resizing --- include/SongEditor.h | 1 - src/core/Track.cpp | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 1f70bece479..8cedd56dc07 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -132,7 +132,6 @@ private slots: positionLine * m_positionLine; ComboBoxModel* m_zoomingModel; - ComboBoxModel* m_snappingModel; bool m_proportionalSnap; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index f8e7c3af2a6..3d5eec585cd 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -914,7 +914,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); } - newPos = max(0, static_cast(newPos)); // Don't go left of bar zero + newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). @@ -960,6 +960,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) int index = std::distance( so.begin(), it ); leftmost = min (leftmost, m_initialOffsets[index].getTicks() ); } + // Make sure the leftmost clip doesn't get moved to a negative position if ( newPos.getTicks() + leftmost < 0 ) { newPos = -leftmost; } for( QVector::iterator it = tcos.begin(); @@ -975,10 +976,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) if( m_action == Resize ) { MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); - if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) - { - t = qMax( MidiTime::ticksPerTact(), t.quantize( gui->songEditor()->m_editor->getSnapSize() ) ); + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position + MidiTime endPos = m_tco->startPosition() + t; + endPos = endPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + t = qMax( 1, endPos - m_tco->startPosition() ); + } + else + { // Otherwise, quantize resize amount + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + t = qMax( MidiTime::ticksPerTact() * snapSize , t.quantize( snapSize ) ); } + m_tco->changeLength( t ); } else @@ -992,13 +1006,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_trackView->trackContainerView()->currentPosition()+ static_cast( x * MidiTime::ticksPerTact() / ppt ) ); - if( ! ( me->modifiers() & Qt::ControlModifier ) - && me->button() == Qt::NoButton ) + if( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) + ) {} + else if( me->modifiers() & Qt::ShiftModifier ) { t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); } + else + { + MidiTime offset = t - m_tco->startPosition(); + offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + t = m_tco->startPosition() + offset; + } + float snapSize = gui->songEditor()->m_editor->getSnapSize(); MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() ) + if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() * snapSize ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -1137,8 +1161,7 @@ void TrackContentObjectView::setInitialOffsets() { continue; } - TrackContentObject * tco = tcov->m_tco; - offsets.push_back( tco->startPosition() - m_initialTCOPos ); + offsets.push_back( tcov->m_tco->startPosition() - m_initialTCOPos ); } m_initialOffsets = offsets; From d879090a408d60e34a6204091890dffbc720d605 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 21 May 2019 22:21:13 +0200 Subject: [PATCH 46/67] Lots of resize fixes --- include/Track.h | 2 ++ src/core/Track.cpp | 72 ++++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/include/Track.h b/include/Track.h index 3c1d3ad5d64..98da13550be 100644 --- a/include/Track.h +++ b/include/Track.h @@ -298,6 +298,7 @@ protected slots: QPoint m_initialMousePos; QPoint m_initialMouseGlobalPos; MidiTime m_initialTCOPos; + MidiTime m_initialTCOEnd; QVector m_initialOffsets; TextFloat * m_hint; @@ -318,6 +319,7 @@ protected slots: m_initialMousePos = pos; m_initialMouseGlobalPos = mapToGlobal( pos ); m_initialTCOPos = m_tco->startPosition(); + m_initialTCOEnd = m_initialTCOPos + m_tco->length(); } void setInitialOffsets(); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 3d5eec585cd..70de16ef27a 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -269,6 +269,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco, m_initialMousePos( QPoint( 0, 0 ) ), m_initialMouseGlobalPos( QPoint( 0, 0 ) ), m_initialTCOPos( MidiTime(0) ), + m_initialTCOEnd( MidiTime(0) ), m_initialOffsets( QVector() ), m_hint( NULL ), m_mutedColor( 0, 0, 0 ), @@ -967,7 +968,6 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) it != tcos.end(); ++it ) { int index = std::distance( tcos.begin(), it ); - //( *it )->movePosition( ( *it )->startPosition() + dtick ); ( *it )->movePosition( newPos + m_initialOffsets[index] ); } } @@ -975,25 +975,34 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { if( m_action == Resize ) { - MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + minLength = MidiTime( 1 ); + } else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position - MidiTime endPos = m_tco->startPosition() + t; - endPos = endPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - t = qMax( 1, endPos - m_tco->startPosition() ); + { // If shift is held, quantize clip's end position + MidiTime end = MidiTime( m_initialTCOPos + l ).quantize( snapSize ); + MidiTime min = m_initialTCOPos.quantize( snapSize ); + if ( min < m_initialTCOPos ) + { min += MidiTime( MidiTime::ticksPerTact() * snapSize ); } + l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); } else - { // Otherwise, quantize resize amount - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - t = qMax( MidiTime::ticksPerTact() * snapSize , t.quantize( snapSize ) ); + { // Otherwise, resize in fixed increments + MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; + MidiTime offset = MidiTime( l - initialLength ).quantize( snapSize ); + MidiTime min = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + l = qMax( min, initialLength + offset); } - - m_tco->changeLength( t ); + l = qMax( minLength, l ); + m_tco->changeLength( l ); } else { @@ -1006,23 +1015,33 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) m_trackView->trackContainerView()->currentPosition()+ static_cast( x * MidiTime::ticksPerTact() / ppt ) ); + float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} - else if( me->modifiers() & Qt::ShiftModifier ) + || (me->modifiers() & Qt::AltModifier) ) { - t = t.quantize( gui->songEditor()->m_editor->getSnapSize() ); + minLength = MidiTime( 1 ); + } + else if( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize clip's start position + MidiTime max = m_initialTCOEnd.quantize( snapSize ); + if ( max > m_initialTCOEnd ) + { max -= MidiTime( 1, 0 ) * snapSize; } + t = qMin( max, t.quantize( snapSize ) ); } else - { - MidiTime offset = t - m_tco->startPosition(); - offset = offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - t = m_tco->startPosition() + offset; + { // Otherwise, resize in fixed increments + MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; + MidiTime minLength = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + MidiTime offset = MidiTime(t - m_initialTCOPos).quantize( snapSize ); + t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); } - float snapSize = gui->songEditor()->m_editor->getSnapSize(); + MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() * snapSize ) + if( m_tco->length() + ( oldPos - t ) >= minLength ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); @@ -1136,7 +1155,6 @@ void TrackContentObjectView::contextMenuEvent( QContextMenuEvent * cme ) - /*! \brief How many pixels a tact (bar) takes for this trackContentObjectView. * * \return the number of pixels per tact (bar). @@ -1147,7 +1165,7 @@ float TrackContentObjectView::pixelsPerTact() } - +/*! \brief Save the offsets between all selected tracks and a clicked track */ void TrackContentObjectView::setInitialOffsets() { QVector so = m_trackView->trackContainerView()->selectedObjects(); @@ -1166,6 +1184,10 @@ void TrackContentObjectView::setInitialOffsets() m_initialOffsets = offsets; } + + + + /*! \brief Detect whether the mouse moved more than n pixels on screen. * * \param _me The QMouseEvent. From d6446e4a51a2ff22b63132fe47d33666a251785d Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 25 May 2019 12:20:45 +0200 Subject: [PATCH 47/67] Preserve latest offset instead of initial offset --- src/core/Track.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 70de16ef27a..2c27928c5da 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -904,8 +904,12 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); @@ -934,8 +938,12 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) - ) {} + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); @@ -977,6 +985,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); + //When snapping, avoid making the new TCO tiny MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize @@ -984,7 +993,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { + //If the user manually makes the TCO tiny, we ĺet them minLength = MidiTime( 1 ); + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position @@ -1016,6 +1029,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) static_cast( x * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); + //When snapping, avoid making the new TCO tiny MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize @@ -1023,7 +1037,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { + //If the user manually makes the TCO tiny, we ĺet them minLength = MidiTime( 1 ); + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); } else if( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's start position From 30c58064da0b21a077b9fa3f8863e55a91a20af5 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 25 May 2019 12:32:19 +0200 Subject: [PATCH 48/67] Refactoring --- include/Track.h | 2 +- src/core/Track.cpp | 79 ++++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/include/Track.h b/include/Track.h index 98da13550be..b00c5024896 100644 --- a/include/Track.h +++ b/include/Track.h @@ -324,7 +324,7 @@ protected slots: void setInitialOffsets(); bool mouseMovedDistance( QMouseEvent * me, int distance ); - + MidiTime draggedTCOPos( QMouseEvent * me ); } ; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 2c27928c5da..3ccde57f174 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -897,27 +897,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); if( m_action == Move ) { - // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; - MidiTime offset = newPos - m_initialTCOPos; - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping - setInitialPos( m_initialMousePos ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - else - { // Otherwise, quantize moved distance (preserves user offsets) - newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } + MidiTime newPos = draggedTCOPos( me ); newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero m_tco->movePosition( newPos ); @@ -931,27 +911,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) else if( m_action == MoveSelection ) { // 1: Find the position we want to move the grabbed TCO to - // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; - MidiTime offset = newPos - m_initialTCOPos; - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping - setInitialPos( m_initialMousePos ); - } - else if ( me->modifiers() & Qt::ShiftModifier ) - { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } - else - { // Otherwise, quantize moved distance (preserves user offsets) - newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); - } + MidiTime newPos = draggedTCOPos( me ); // 2: Handle moving the other selected TCOs the same distance QVector so = @@ -1220,6 +1180,41 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance +/*! \bried Calculate the new position of a dragged TCO from a mouse event + * + * + * \param me The QMouseEvent + */ +MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) +{ + //Pixels per tact + const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); + // The pixel position of the mouse, adjusted for where the clip was grabbed + const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + MidiTime offset = newPos - m_initialTCOPos; + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + if ( me->button() != Qt::NoButton + || (me->modifiers() & Qt::ControlModifier) + || (me->modifiers() & Qt::AltModifier) ) + { + // We want to preserve this adjusted offset, + // even if the user switches to snapping + setInitialPos( m_initialMousePos ); + } + else if ( me->modifiers() & Qt::ShiftModifier ) + { // If shift is held, quantize position (Default in 1.2.0 and earlier) + newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + else + { // Otherwise, quantize moved distance (preserves user offsets) + newPos = m_initialTCOPos + offset.quantize( gui->songEditor()->m_editor->getSnapSize() ); + } + return newPos; +} + + + // =========================================================================== // trackContentWidget From 56bb8ab6b387cf33b21367e8ed7f4bf7fc1441c3 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 27 May 2019 15:29:59 +0200 Subject: [PATCH 49/67] Typo fix 1 --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 730cced9377..dc48c6798b9 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -777,7 +777,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setToolTip(tr("Clip snapping")); m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), - tr("Toggle roportional snap on/off"), this); + tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(true); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); From b197bdc322981e56a59de5cc16e56bc8e343841e Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 27 May 2019 15:30:30 +0200 Subject: [PATCH 50/67] Typo fix 2 --- src/core/Track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 3ccde57f174..348c23d446c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1180,7 +1180,7 @@ bool TrackContentObjectView::mouseMovedDistance( QMouseEvent * me, int distance -/*! \bried Calculate the new position of a dragged TCO from a mouse event +/*! \brief Calculate the new position of a dragged TCO from a mouse event * * * \param me The QMouseEvent From ef8b8cba2143950342dcd5436e58cd35eee13bfc Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 29 May 2019 10:58:52 +0200 Subject: [PATCH 51/67] Fix offset when scrolled --- src/core/Track.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 348c23d446c..0bca31041b3 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1190,8 +1190,9 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) //Pixels per tact const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); // The pixel position of the mouse, adjusted for where the clip was grabbed - const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - MidiTime newPos = mousePos * MidiTime::ticksPerTact() / ppt; + //const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); + const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); //Always starts on bar 1 + MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton From ef14bf115cdae2ee48914abae9516f36b06ed52d Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 29 May 2019 11:04:53 +0200 Subject: [PATCH 52/67] Clean up --- src/core/Track.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 0bca31041b3..278b505f930 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1189,9 +1189,8 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) { //Pixels per tact const float ppt = m_trackView->trackContainerView()->pixelsPerTact(); - // The pixel position of the mouse, adjusted for where the clip was grabbed - //const int mousePos = mapToParent(me->pos()).x() - m_initialMousePos.x(); - const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); //Always starts on bar 1 + // The pixel distance that the mouse has moved + const int mouseOff = mapToGlobal(me->pos()).x() - m_initialMouseGlobalPos.x(); MidiTime newPos = m_initialTCOPos + mouseOff * MidiTime::ticksPerTact() / ppt; MidiTime offset = newPos - m_initialTCOPos; // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize From e6b9c58ac82dfa63a56ad1a8845e90f222d92a69 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 17:24:34 +0200 Subject: [PATCH 53/67] BaraMGB's suggestions from code review Except the comment positioning, holding out for a response on that. --- src/core/Track.cpp | 1 - src/gui/editors/SongEditor.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 278b505f930..710cb18eb48 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include "AutomationPattern.h" diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index dc48c6798b9..7ee18b7eaf5 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include "AutomatableSlider.h" #include "ComboBox.h" @@ -283,7 +282,8 @@ float SongEditor::getSnapSize() const{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; // If proportional snap is on, we snap to finer values when zoomed in - if (m_proportionalSnap){ + if (m_proportionalSnap) + { val = val - m_zoomingModel->value() + 3; } val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. From d24715e199ed8e4a4ebbb6b3dac0932f11722134 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 17:29:41 +0200 Subject: [PATCH 54/67] More code review --- src/core/Track.cpp | 3 ++- src/gui/editors/SongEditor.cpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 710cb18eb48..de3cac89645 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -898,7 +898,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { MidiTime newPos = draggedTCOPos( me ); - newPos = max( 0, newPos.getTicks() ); // Don't go left of bar zero + // Don't go left of bar zero + newPos = max( 0, newPos.getTicks() ); m_tco->movePosition( newPos ); m_trackView->getTrackContentWidget()->changePosition(); s_textFloat->setText( QString( "%1:%2" ). diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 7ee18b7eaf5..e727271c92e 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -244,14 +244,18 @@ SongEditor::SongEditor( Song * song ) : this, SLOT( zoomingChanged() ) ); //Set up snapping model, 2^i - for ( int i = 3; i >= -4; i-- ){ - if ( i > 0 ){ + for ( int i = 3; i >= -4; i-- ) + { + if ( i > 0 ) + { m_snappingModel->addItem( QString( "%1 Bars").arg( 1 << i ) ); } - else if ( i == 0 ){ + else if ( i == 0 ) + { m_snappingModel->addItem( "1 Bar" ); } - else { + else + { m_snappingModel->addItem( QString( "1/%1 Bar" ).arg( 1 << (-i) ) ); } } From 3b979b357107534184a938a744f023f02087ad85 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 18:17:34 +0200 Subject: [PATCH 55/67] Proportional Snap Icon (classic) --- data/themes/classic/proportional_snap.png | Bin 0 -> 263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/classic/proportional_snap.png diff --git a/data/themes/classic/proportional_snap.png b/data/themes/classic/proportional_snap.png new file mode 100644 index 0000000000000000000000000000000000000000..66a0bb0493411d97d9a3e3b22cd779afeb0d89f2 GIT binary patch literal 263 zcmV+i0r>ujP)w8hB+L*W8jWMdbMaYZ01 Date: Sun, 2 Jun 2019 18:17:57 +0200 Subject: [PATCH 56/67] Proportional Snap Icon (default) --- data/themes/default/proportional_snap.png | Bin 0 -> 263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/default/proportional_snap.png diff --git a/data/themes/default/proportional_snap.png b/data/themes/default/proportional_snap.png new file mode 100644 index 0000000000000000000000000000000000000000..66a0bb0493411d97d9a3e3b22cd779afeb0d89f2 GIT binary patch literal 263 zcmV+i0r>ujP)w8hB+L*W8jWMdbMaYZ01 Date: Sun, 2 Jun 2019 18:19:48 +0200 Subject: [PATCH 57/67] Update proportional snap pixmap --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index e727271c92e..ea6e0f57356 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -780,7 +780,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox->setModel(m_editor->m_snappingModel); m_snappingComboBox->setToolTip(tr("Clip snapping")); - m_setProportionalSnapAction = new QAction(embed::getIconPixmap("add_automation"), + m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(true); From d0ba76316c689f9dd373208fa77fcdff86825ac4 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 2 Jun 2019 20:03:56 +0200 Subject: [PATCH 58/67] Proportional snap off by default --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index ea6e0f57356..7d84957a27b 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -783,7 +783,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); - m_setProportionalSnapAction->setChecked(true); + m_setProportionalSnapAction->setChecked(false); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); snapToolBar->addWidget( snap_lbl ); From b10503e3acd4ea2167b621560d7799a9a63b4bd2 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:47:00 +0200 Subject: [PATCH 59/67] Display snap level when proportional snap enabled --- include/SongEditor.h | 6 +++- src/gui/editors/SongEditor.cpp | 58 +++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/include/SongEditor.h b/include/SongEditor.h index 8cedd56dc07..8a02d56919a 100644 --- a/include/SongEditor.h +++ b/include/SongEditor.h @@ -73,7 +73,9 @@ class SongEditor : public TrackContainerView void loadSettings( const QDomElement& element ); ComboBoxModel *zoomingModel() const; + ComboBoxModel *snappingModel() const; float getSnapSize() const; + QString getSnapSizeString() const; public slots: void scrolled( int new_pos ); @@ -145,7 +147,6 @@ private slots: EditMode m_ctrlMode; // mode they were in before they hit ctrl friend class SongEditorWindow; - } ; @@ -174,6 +175,8 @@ protected slots: void lostFocus(); void adjustUiAfterProjectLoad(); + void updateSnapLabel(); + signals: void playTriggered(); void resized(); @@ -194,6 +197,7 @@ protected slots: ComboBox * m_zoomingComboBox; ComboBox * m_snappingComboBox; + QLabel* m_snapSizeLabel; }; #endif diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 7d84957a27b..f19aadca9f6 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -282,7 +282,11 @@ void SongEditor::loadSettings( const QDomElement& element ) MainWindow::restoreWidgetState(parentWidget(), element); } -float SongEditor::getSnapSize() const{ + + + +float SongEditor::getSnapSize() const +{ // 1 Bar is the third value in the snapping dropdown int val = -m_snappingModel->value() + 3; // If proportional snap is on, we snap to finer values when zoomed in @@ -300,6 +304,24 @@ float SongEditor::getSnapSize() const{ } } +QString SongEditor::getSnapSizeString() const +{ + int val = -m_snappingModel->value() + 3; + val = val - m_zoomingModel->value() + 3; + val = max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. + + if ( val >= 0 ){ + int bars = 1 << val; + return QString( "%1 Bar" ).arg(bars); + } + else { + int div = ( 1 << -val ); + return QString( "1/%1 Bar" ).arg(div); + } +} + + + void SongEditor::setHighQuality( bool hq ) { @@ -695,10 +717,19 @@ ComboBoxModel *SongEditor::zoomingModel() const +ComboBoxModel *SongEditor::snappingModel() const +{ + return m_snappingModel; +} + + + + SongEditorWindow::SongEditorWindow(Song* song) : Editor(Engine::mixer()->audioDev()->supportsCapture(), false), m_editor(new SongEditor(song)), - m_crtlAction( NULL ) + m_crtlAction( NULL ), + m_snapSizeLabel( new QLabel( m_toolBar ) ) { setWindowTitle( tr( "Song-Editor" ) ); setWindowIcon( embed::getIconPixmap( "songeditor" ) ); @@ -766,6 +797,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_zoomingComboBox->move( 580, 4 ); m_zoomingComboBox->setModel(m_editor->m_zoomingModel); m_zoomingComboBox->setToolTip(tr("Horizontal zooming")); + connect(m_editor->zoomingModel(), SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); zoomToolBar->addWidget( zoom_lbl ); zoomToolBar->addWidget( m_zoomingComboBox ); @@ -778,26 +810,44 @@ SongEditorWindow::SongEditorWindow(Song* song) : m_snappingComboBox = new ComboBox( m_toolBar ); m_snappingComboBox->setFixedSize( 80, 22 ); m_snappingComboBox->setModel(m_editor->m_snappingModel); - m_snappingComboBox->setToolTip(tr("Clip snapping")); + m_snappingComboBox->setToolTip(tr("Clip snapping size")); + connect(m_editor->snappingModel(), SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); m_setProportionalSnapAction = new QAction(embed::getIconPixmap("proportional_snap"), tr("Toggle proportional snap on/off"), this); m_setProportionalSnapAction->setCheckable(true); m_setProportionalSnapAction->setChecked(false); connect(m_setProportionalSnapAction, SIGNAL(triggered()), m_editor, SLOT(toggleProportionalSnap())); + connect(m_setProportionalSnapAction, SIGNAL(triggered()), this, SLOT(updateSnapLabel()) ); snapToolBar->addWidget( snap_lbl ); snapToolBar->addWidget( m_snappingComboBox ); snapToolBar->addSeparator(); snapToolBar->addAction( m_setProportionalSnapAction ); + snapToolBar->addSeparator(); + snapToolBar->addWidget( m_snapSizeLabel ); + connect(song, SIGNAL(projectLoaded()), this, SLOT(adjustUiAfterProjectLoad())); connect(this, SIGNAL(resized()), m_editor, SLOT(updatePositionLine())); } QSize SongEditorWindow::sizeHint() const { - return {640, 300}; + return {720, 300}; +} + +void SongEditorWindow::updateSnapLabel(){ + if (m_setProportionalSnapAction->isChecked()) + { + m_snapSizeLabel->setText(QString("Snap: ") + m_editor->getSnapSizeString()); + m_snappingComboBox->setToolTip(tr("Base snapping size")); + } + else + { + m_snappingComboBox->setToolTip(tr("Clip snapping size")); + m_snapSizeLabel->clear(); + } } From eea5a718181ec30ec30c128589988b23570ebeb4 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:48:49 +0200 Subject: [PATCH 60/67] Make proportional snap false at initialization --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index f19aadca9f6..2bf29dbbba7 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -77,7 +77,7 @@ SongEditor::SongEditor( Song * song ) : m_song( song ), m_zoomingModel(new ComboBoxModel()), m_snappingModel(new ComboBoxModel()), - m_proportionalSnap( true ), + m_proportionalSnap( false ), m_scrollBack( false ), m_smoothScroll( ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt() ), m_mode(DrawMode) From a261a0a6cc7149571658feabd6d49a6501ddca37 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 22:53:26 +0200 Subject: [PATCH 61/67] Plurals in snap size label --- src/gui/editors/SongEditor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 2bf29dbbba7..4a7fadc4ea9 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -312,7 +312,11 @@ QString SongEditor::getSnapSizeString() const if ( val >= 0 ){ int bars = 1 << val; - return QString( "%1 Bar" ).arg(bars); + if ( bars == 1 ) { return QString("1 Bar"); + else + { + QString( "%1 Bars" ).arg(bars); + } } else { int div = ( 1 << -val ); From ff93fc9e7b4ccc26a85a90d16c4278599e23dc22 Mon Sep 17 00:00:00 2001 From: Spekular Date: Mon, 10 Jun 2019 23:02:54 +0200 Subject: [PATCH 62/67] Add missing "return" --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 4a7fadc4ea9..6ed090a74b1 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -315,7 +315,7 @@ QString SongEditor::getSnapSizeString() const if ( bars == 1 ) { return QString("1 Bar"); else { - QString( "%1 Bars" ).arg(bars); + return QString( "%1 Bars" ).arg(bars); } } else { From cc3edb6d1834081fcb7e82d9e3093b93eddab665 Mon Sep 17 00:00:00 2001 From: Spekular Date: Tue, 11 Jun 2019 10:08:56 +0200 Subject: [PATCH 63/67] Update src/gui/editors/SongEditor.cpp Co-Authored-By: Hyunjin Song --- src/gui/editors/SongEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 6ed090a74b1..6e23fcdbef7 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -312,7 +312,7 @@ QString SongEditor::getSnapSizeString() const if ( val >= 0 ){ int bars = 1 << val; - if ( bars == 1 ) { return QString("1 Bar"); + if ( bars == 1 ) { return QString("1 Bar"); } else { return QString( "%1 Bars" ).arg(bars); From 0ee09b53afa2671416014a48a1aa5f5275d90f00 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 22 Jun 2019 15:53:32 +0200 Subject: [PATCH 64/67] Better resize limits --- src/core/Track.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index de3cac89645..c81f19fd66c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -943,38 +943,39 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) { if( m_action == Resize ) { - MidiTime l = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + MidiTime l = static_cast( me->x() * MidiTime::ticksPerTact() / ppt ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); - //When snapping, avoid making the new TCO tiny - MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // Length in ticks of one snap increment + MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if ( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { - //If the user manually makes the TCO tiny, we ĺet them - minLength = MidiTime( 1 ); // We want to preserve this adjusted offset, // even if the user switches to snapping setInitialPos( m_initialMousePos ); + // Don't resize to less than 1 tick + l = qMax( 1, l ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position MidiTime end = MidiTime( m_initialTCOPos + l ).quantize( snapSize ); + // The end position has to be after the clip's start MidiTime min = m_initialTCOPos.quantize( snapSize ); - if ( min < m_initialTCOPos ) - { min += MidiTime( MidiTime::ticksPerTact() * snapSize ); } + if ( min <= m_initialTCOPos ) min += snapLength; l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); } else { // Otherwise, resize in fixed increments MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; MidiTime offset = MidiTime( l - initialLength ).quantize( snapSize ); - MidiTime min = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + // Don't resize to less than 1 tick + MidiTime min = MidiTime( initialLength % snapLength ); + if (min < 1) min += snapLength; l = qMax( min, initialLength + offset); } - l = qMax( minLength, l ); m_tco->changeLength( l ); } else @@ -989,37 +990,39 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) static_cast( x * MidiTime::ticksPerTact() / ppt ) ); float snapSize = gui->songEditor()->m_editor->getSnapSize(); - //When snapping, avoid making the new TCO tiny - MidiTime minLength = MidiTime( MidiTime::ticksPerTact() / 16 ); + // Length in ticks of one snap increment + MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize if( me->button() != Qt::NoButton || (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier) ) { - //If the user manually makes the TCO tiny, we ĺet them - minLength = MidiTime( 1 ); // We want to preserve this adjusted offset, // even if the user switches to snapping setInitialPos( m_initialMousePos ); + //Don't resize to less than 1 tick + t = qMin( m_initialTCOEnd - 1, t); } else if( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's start position + // Don't let the start position move past the end position MidiTime max = m_initialTCOEnd.quantize( snapSize ); - if ( max > m_initialTCOEnd ) - { max -= MidiTime( 1, 0 ) * snapSize; } + if ( max >= m_initialTCOEnd ) max -= snapLength; t = qMin( max, t.quantize( snapSize ) ); } else { // Otherwise, resize in fixed increments + // Don't resize to less than 1 tick MidiTime initialLength = m_initialTCOEnd - m_initialTCOPos; - MidiTime minLength = MidiTime( initialLength % (int)(MidiTime::ticksPerTact() * snapSize) ); + MidiTime minLength = MidiTime( initialLength % snapLength ); + if (minLength < 1) minLength += snapLength; MidiTime offset = MidiTime(t - m_initialTCOPos).quantize( snapSize ); t = qMin( m_initialTCOEnd - minLength, m_initialTCOPos + offset ); } MidiTime oldPos = m_tco->startPosition(); - if( m_tco->length() + ( oldPos - t ) >= minLength ) + if( m_tco->length() + ( oldPos - t ) >= 1 ) { m_tco->movePosition( t ); m_trackView->getTrackContentWidget()->changePosition(); From bac1541f834a3f7f67dfee22608959d1d036e736 Mon Sep 17 00:00:00 2001 From: Spekular Date: Wed, 26 Jun 2019 19:16:19 +0200 Subject: [PATCH 65/67] Consolidation attempt --- src/core/Track.cpp | 47 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index c81f19fd66c..6fb93245191 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -941,23 +941,23 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == Resize || m_action == ResizeLeft ) { + // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize + const bool unquantized = (me->modifiers() & Qt::ControlModifier) || (me->modifiers() & Qt::AltModifier); + const float snapSize = gui->songEditor()->m_editor->getSnapSize(); + // Length in ticks of one snap increment + const MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); + if( m_action == Resize ) { + // The clip's new length MidiTime l = static_cast( me->x() * MidiTime::ticksPerTact() / ppt ); - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - // Length in ticks of one snap increment - MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); - - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if ( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping + + if ( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later setInitialPos( m_initialMousePos ); // Don't resize to less than 1 tick - l = qMax( 1, l ); + m_tco->changeLength( qMax( 1, l ) ); } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize clip's end position @@ -965,7 +965,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // The end position has to be after the clip's start MidiTime min = m_initialTCOPos.quantize( snapSize ); if ( min <= m_initialTCOPos ) min += snapLength; - l = qMax(min - m_initialTCOPos, end - m_initialTCOPos); + m_tco->changeLength( qMax(min - m_initialTCOPos, end - m_initialTCOPos) ); } else { // Otherwise, resize in fixed increments @@ -974,9 +974,8 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) // Don't resize to less than 1 tick MidiTime min = MidiTime( initialLength % snapLength ); if (min < 1) min += snapLength; - l = qMax( min, initialLength + offset); + m_tco->changeLength( qMax( min, initialLength + offset) ); } - m_tco->changeLength( l ); } else { @@ -987,19 +986,11 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) MidiTime t = qMax( 0, (int) m_trackView->trackContainerView()->currentPosition()+ - static_cast( x * MidiTime::ticksPerTact() / - ppt ) ); - float snapSize = gui->songEditor()->m_editor->getSnapSize(); - // Length in ticks of one snap increment - MidiTime snapLength = MidiTime( (int)(snapSize * MidiTime::ticksPerTact()) ); - - // If the user is holding alt, or pressed ctrl after beginning the drag, don't quantize - if( me->button() != Qt::NoButton - || (me->modifiers() & Qt::ControlModifier) - || (me->modifiers() & Qt::AltModifier) ) - { - // We want to preserve this adjusted offset, - // even if the user switches to snapping + static_cast( x * MidiTime::ticksPerTact() / ppt ) ); + + if( unquantized ) + { // We want to preserve this adjusted offset, + // even if the user switches to snapping later setInitialPos( m_initialMousePos ); //Don't resize to less than 1 tick t = qMin( m_initialTCOEnd - 1, t); From dbc90b6dfa543027ac2ee876a50a3d32347aecfc Mon Sep 17 00:00:00 2001 From: Spekular Date: Fri, 12 Jul 2019 21:48:41 +0200 Subject: [PATCH 66/67] Also snap end position in shift mode --- src/core/Track.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 6fb93245191..fe66ab4a5e5 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1198,7 +1198,15 @@ MidiTime TrackContentObjectView::draggedTCOPos( QMouseEvent * me ) } else if ( me->modifiers() & Qt::ShiftModifier ) { // If shift is held, quantize position (Default in 1.2.0 and earlier) - newPos = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + // or end position, whichever is closest to the actual position + MidiTime startQ = newPos.quantize( gui->songEditor()->m_editor->getSnapSize() ); + // Find start position that gives snapped clip end position + MidiTime endQ = ( newPos + m_tco->length() ); + endQ = endQ.quantize( gui->songEditor()->m_editor->getSnapSize() ); + endQ = endQ - m_tco->length(); + // Select the position closest to actual position + if ( abs(newPos - startQ) < abs(newPos - endQ) ) newPos = startQ; + else newPos = endQ; } else { // Otherwise, quantize moved distance (preserves user offsets) From 0ca935839943e6109dc726266976219dc910a1c3 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sat, 13 Jul 2019 18:49:52 +0200 Subject: [PATCH 67/67] Fix for changes on master --- src/tracks/SampleTrack.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index ea3c5360249..4b51ef6ec65 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -529,7 +529,7 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) float nom = Engine::getSong()->getTimeSigModel().getNumerator(); float den = Engine::getSong()->getTimeSigModel().getDenominator(); float ticksPerTact = DefaultTicksPerTact * nom / den; - + float offset = m_tco->startTimeOffset() / ticksPerTact * pixelsPerTact(); QRect r = QRect( TCO_BORDER_WIDTH + offset, spacing, qMax( static_cast( m_tco->sampleLength() * ppt / ticksPerTact ), 1 ), rect().bottom() - 2 * spacing ); @@ -931,7 +931,7 @@ void SampleTrackView::dropEvent(QDropEvent *de) ? MidiTime(0) : MidiTime(((xPos - trackHeadWidth) / trackContainerView()->pixelsPerTact() * MidiTime::ticksPerTact()) + trackContainerView()->currentPosition() - ).toNearestTact(); + ).quantize(1.0); SampleTCO * sTco = static_cast(getTrack()->createTCO(tcoPos)); if (sTco) { sTco->setSampleFile(value); } @@ -1192,4 +1192,3 @@ void SampleTrackWindow::loadSettings(const QDomElement& element) m_stv->m_tlb->setChecked(true); } } -