Add Continuous Auto-Scrolling (#7396)
* Initial Commit * Refactor code and add new icons * Fix logical error * Add smooth scrolling to Song Editor * Remove unused variable * Fix scrolling speed and scrollbar width * Remove QDebug and re-add a newline I deleted in an unrelated file * Forgot to add files to commit * Remove unused variable * Fix Styling * Fix Styling Again * Fix Styling Again * Fix Styling Again * Add icons for classic theme * Accidentally committed varying scroll speed with zoom -- removing * Change abs to std::abs Co-authored-by: saker <sakertooth@gmail.com> * Change qMax to std::max and use static_cast Co-authored-by: saker <sakertooth@gmail.com> * Simplify stepped auto scrolling Co-authored-by: saker <sakertooth@gmail.com> * Remove unnecessary parentheses * Remove return statement causing the play head line to stop * Add specific tooltips to auto scrolling button states * Remove `== true` from SongEditor.cpp Co-authored-by: saker <sakertooth@gmail.com> * Make tooltips translatable Co-authored-by: Dominic Clark <mrdomclark@gmail.com> * Fix zooming position calculation * Rename bars to ticks * Fix rubberband rect size --------- Co-authored-by: saker <sakertooth@gmail.com> Co-authored-by: Dominic Clark <mrdomclark@gmail.com>
This commit is contained in:
BIN
data/themes/classic/autoscroll_continuous_on.png
Normal file
BIN
data/themes/classic/autoscroll_continuous_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
BIN
data/themes/classic/autoscroll_stepped_on.png
Normal file
BIN
data/themes/classic/autoscroll_stepped_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
data/themes/default/autoscroll_continuous_on.png
Normal file
BIN
data/themes/default/autoscroll_continuous_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
BIN
data/themes/default/autoscroll_stepped_on.png
Normal file
BIN
data/themes/default/autoscroll_stepped_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -73,7 +73,8 @@ public:
|
||||
|
||||
enum class AutoScrollState
|
||||
{
|
||||
Enabled,
|
||||
Stepped,
|
||||
Continuous,
|
||||
Disabled
|
||||
};
|
||||
|
||||
@@ -212,7 +213,7 @@ private:
|
||||
QCursor m_cursorSelectLeft = QCursor{embed::getIconPixmap("cursor_select_left"), 0, 16};
|
||||
QCursor m_cursorSelectRight = QCursor{embed::getIconPixmap("cursor_select_right"), 32, 16};
|
||||
|
||||
AutoScrollState m_autoScroll = AutoScrollState::Enabled;
|
||||
AutoScrollState m_autoScroll = AutoScrollState::Stepped;
|
||||
|
||||
// Width of the unused region on the widget's left (above track labels or piano)
|
||||
int m_xOffset;
|
||||
|
||||
@@ -4062,7 +4062,7 @@ void PianoRoll::stop()
|
||||
{
|
||||
Engine::getSong()->stop();
|
||||
m_recording = false;
|
||||
m_scrollBack = ( m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Enabled );
|
||||
m_scrollBack = m_timeLine->autoScroll() != TimeLineWidget::AutoScrollState::Disabled;
|
||||
}
|
||||
|
||||
|
||||
@@ -4463,30 +4463,36 @@ bool PianoRoll::deleteSelectedNotes()
|
||||
void PianoRoll::autoScroll( const TimePos & t )
|
||||
{
|
||||
const int w = width() - m_whiteKeyWidth;
|
||||
if( t > m_currentPosition + w * TimePos::ticksPerBar() / m_ppb )
|
||||
if (m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Stepped)
|
||||
{
|
||||
m_leftRightScroll->setValue( t.getBar() * TimePos::ticksPerBar() );
|
||||
if (t > m_currentPosition + w * TimePos::ticksPerBar() / m_ppb)
|
||||
{
|
||||
m_leftRightScroll->setValue(t.getBar() * TimePos::ticksPerBar());
|
||||
}
|
||||
else if (t < m_currentPosition)
|
||||
{
|
||||
TimePos t2 = std::max(t - w * TimePos::ticksPerBar() *
|
||||
TimePos::ticksPerBar() / m_ppb, static_cast<tick_t>(0));
|
||||
m_leftRightScroll->setValue(t2.getBar() * TimePos::ticksPerBar());
|
||||
}
|
||||
}
|
||||
else if( t < m_currentPosition )
|
||||
else if (m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Continuous)
|
||||
{
|
||||
TimePos t2 = qMax( t - w * TimePos::ticksPerBar() *
|
||||
TimePos::ticksPerBar() / m_ppb, (tick_t) 0 );
|
||||
m_leftRightScroll->setValue( t2.getBar() * TimePos::ticksPerBar() );
|
||||
m_leftRightScroll->setValue(std::max(t.getTicks() - w * TimePos::ticksPerBar() / m_ppb / 2, 0));
|
||||
}
|
||||
m_scrollBack = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void PianoRoll::updatePosition( const TimePos & t )
|
||||
void PianoRoll::updatePosition(const TimePos & t)
|
||||
{
|
||||
if( ( Engine::getSong()->isPlaying()
|
||||
if ((Engine::getSong()->isPlaying()
|
||||
&& Engine::getSong()->playMode() == Song::PlayMode::MidiClip
|
||||
&& m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Enabled
|
||||
) || m_scrollBack )
|
||||
&& m_timeLine->autoScroll() != TimeLineWidget::AutoScrollState::Disabled
|
||||
) || m_scrollBack)
|
||||
{
|
||||
autoScroll( t );
|
||||
autoScroll(t);
|
||||
}
|
||||
// ticks relative to m_currentPosition
|
||||
// < 0 = outside viewport left
|
||||
|
||||
@@ -231,10 +231,10 @@ SongEditor::SongEditor( Song * song ) :
|
||||
static_cast<QVBoxLayout *>( layout() )->insertWidget( 0, m_timeLine );
|
||||
|
||||
m_leftRightScroll = new QScrollBar( Qt::Horizontal, this );
|
||||
m_leftRightScroll->setMinimum( 0 );
|
||||
m_leftRightScroll->setMaximum( 0 );
|
||||
m_leftRightScroll->setSingleStep( 1 );
|
||||
m_leftRightScroll->setPageStep( 20 );
|
||||
m_leftRightScroll->setMinimum(0);
|
||||
m_leftRightScroll->setMaximum(0);
|
||||
m_leftRightScroll->setSingleStep(1);
|
||||
m_leftRightScroll->setPageStep(20 * TimePos::ticksPerBar());
|
||||
static_cast<QVBoxLayout *>( layout() )->addWidget( m_leftRightScroll );
|
||||
connect( m_leftRightScroll, SIGNAL(valueChanged(int)),
|
||||
this, SLOT(scrolled(int)));
|
||||
@@ -325,7 +325,7 @@ QString SongEditor::getSnapSizeString() const
|
||||
void SongEditor::scrolled( int new_pos )
|
||||
{
|
||||
update();
|
||||
emit positionChanged( m_currentPosition = TimePos( new_pos, 0 ) );
|
||||
emit positionChanged(m_currentPosition = TimePos(new_pos));
|
||||
}
|
||||
|
||||
|
||||
@@ -384,7 +384,7 @@ void SongEditor::updateRubberband()
|
||||
}
|
||||
|
||||
//take care of the scrollbar position
|
||||
int hs = (m_leftRightScroll->value() - m_scrollPos.x()) * pixelsPerBar();
|
||||
int hs = (m_leftRightScroll->value() - m_scrollPos.x()) * pixelsPerBar() / TimePos::ticksPerBar();
|
||||
int vs = contentWidget()->verticalScrollBar()->value() - m_scrollPos.y();
|
||||
|
||||
//the adjusted origin point
|
||||
@@ -522,8 +522,8 @@ void SongEditor::wheelEvent( QWheelEvent * we )
|
||||
if ((we->modifiers() & Qt::ControlModifier) && (position(we).x() > m_trackHeadWidth))
|
||||
{
|
||||
int x = position(we).x() - m_trackHeadWidth;
|
||||
// bar based on the mouse x-position where the scroll wheel was used
|
||||
int bar = x / pixelsPerBar();
|
||||
// tick based on the mouse x-position where the scroll wheel was used
|
||||
int tick = x / pixelsPerBar() * TimePos::ticksPerBar();
|
||||
|
||||
// move zoom slider (pixelsPerBar will change automatically)
|
||||
int step = we->modifiers() & Qt::ShiftModifier ? 1 : 5;
|
||||
@@ -531,9 +531,9 @@ void SongEditor::wheelEvent( QWheelEvent * we )
|
||||
int direction = (we->angleDelta().y() + we->angleDelta().x()) > 0 ? 1 : -1;
|
||||
m_zoomingModel->incValue(step * direction);
|
||||
|
||||
// scroll to zooming around cursor's bar
|
||||
int newBar = static_cast<int>(x / pixelsPerBar());
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value() + bar - newBar);
|
||||
// scroll to zooming around cursor's tick
|
||||
int newTick = static_cast<int>(x / pixelsPerBar() * TimePos::ticksPerBar());
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value() + tick - newTick);
|
||||
|
||||
// update timeline
|
||||
m_timeLine->setPixelsPerBar(pixelsPerBar());
|
||||
@@ -542,15 +542,15 @@ void SongEditor::wheelEvent( QWheelEvent * we )
|
||||
}
|
||||
|
||||
// FIXME: Reconsider if determining orientation is necessary in Qt6.
|
||||
else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal
|
||||
else if (std::abs(we->angleDelta().x()) > std::abs(we->angleDelta().y())) // scrolling is horizontal
|
||||
{
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value() -
|
||||
we->angleDelta().x() /30);
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value()
|
||||
- we->angleDelta().x());
|
||||
}
|
||||
else if(we->modifiers() & Qt::ShiftModifier)
|
||||
else if (we->modifiers() & Qt::ShiftModifier)
|
||||
{
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value() -
|
||||
we->angleDelta().y() / 30);
|
||||
m_leftRightScroll->setValue(m_leftRightScroll->value()
|
||||
- we->angleDelta().y());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -711,9 +711,9 @@ void SongEditor::hideMasterPitchFloat( void )
|
||||
|
||||
|
||||
|
||||
void SongEditor::updateScrollBar( int len )
|
||||
void SongEditor::updateScrollBar(int len)
|
||||
{
|
||||
m_leftRightScroll->setMaximum( len );
|
||||
m_leftRightScroll->setMaximum(len * TimePos::ticksPerBar());
|
||||
}
|
||||
|
||||
|
||||
@@ -756,22 +756,25 @@ void SongEditor::updatePosition( const TimePos & t )
|
||||
const auto widgetWidth = compactTrackButtons ? DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT : DEFAULT_SETTINGS_WIDGET_WIDTH;
|
||||
const auto trackOpWidth = compactTrackButtons ? TRACK_OP_WIDTH_COMPACT : TRACK_OP_WIDTH;
|
||||
|
||||
if( ( m_song->isPlaying() && m_song->m_playMode == Song::PlayMode::Song
|
||||
&& m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Enabled) ||
|
||||
m_scrollBack == true )
|
||||
if ((m_song->isPlaying() && m_song->m_playMode == Song::PlayMode::Song)
|
||||
|| m_scrollBack)
|
||||
{
|
||||
m_smoothScroll = ConfigManager::inst()->value( "ui", "smoothscroll" ).toInt();
|
||||
const int w = width() - widgetWidth
|
||||
- trackOpWidth
|
||||
- contentWidget()->verticalScrollBar()->width(); // width of right scrollbar
|
||||
if( t > m_currentPosition + w * TimePos::ticksPerBar() /
|
||||
pixelsPerBar() )
|
||||
|
||||
if (m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Stepped)
|
||||
{
|
||||
animateScroll( m_leftRightScroll, t.getBar(), m_smoothScroll );
|
||||
const auto nextPosition = m_currentPosition + w * TimePos::ticksPerBar() / pixelsPerBar();
|
||||
if (t > nextPosition || t < m_currentPosition)
|
||||
{
|
||||
animateScroll(m_leftRightScroll, t.getTicks(), m_smoothScroll);
|
||||
}
|
||||
}
|
||||
else if( t < m_currentPosition )
|
||||
else if (m_timeLine->autoScroll() == TimeLineWidget::AutoScrollState::Continuous)
|
||||
{
|
||||
animateScroll( m_leftRightScroll, t.getBar(), m_smoothScroll );
|
||||
animateScroll(m_leftRightScroll, std::max(t.getTicks() - w * TimePos::ticksPerBar() / pixelsPerBar() / 2, 0.0f), m_smoothScroll);
|
||||
}
|
||||
m_scrollBack = false;
|
||||
}
|
||||
|
||||
@@ -88,9 +88,10 @@ void TimeLineWidget::setXOffset(const int x)
|
||||
void TimeLineWidget::addToolButtons( QToolBar * _tool_bar )
|
||||
{
|
||||
auto autoScroll = new NStateButton(_tool_bar);
|
||||
autoScroll->setGeneralToolTip( tr( "Auto scrolling" ) );
|
||||
autoScroll->addState( embed::getIconPixmap( "autoscroll_on" ) );
|
||||
autoScroll->addState( embed::getIconPixmap( "autoscroll_off" ) );
|
||||
autoScroll->setGeneralToolTip(tr("Auto scrolling"));
|
||||
autoScroll->addState(embed::getIconPixmap("autoscroll_stepped_on"), tr("Stepped auto scrolling"));
|
||||
autoScroll->addState(embed::getIconPixmap("autoscroll_continuous_on"), tr("Continuous auto scrolling"));
|
||||
autoScroll->addState(embed::getIconPixmap("autoscroll_off"), tr("Auto scrolling disabled"));
|
||||
connect( autoScroll, SIGNAL(changedState(int)), this,
|
||||
SLOT(toggleAutoScroll(int)));
|
||||
|
||||
|
||||
@@ -292,6 +292,7 @@ void TrackContentWidget::changePosition( const TimePos & newPos )
|
||||
setUpdatesEnabled( true );
|
||||
|
||||
// redraw background
|
||||
updateBackground();
|
||||
// update();
|
||||
}
|
||||
|
||||
@@ -628,8 +629,8 @@ void TrackContentWidget::paintEvent( QPaintEvent * pe )
|
||||
// Don't draw background on Pattern Editor
|
||||
if (m_trackView->trackContainerView() != getGUI()->patternEditor()->m_editor)
|
||||
{
|
||||
p.drawTiledPixmap( rect(), m_background, QPoint(
|
||||
tcv->currentPosition().getBar() * ppb, 0 ) );
|
||||
p.drawTiledPixmap(rect(), m_background, QPoint(
|
||||
tcv->currentPosition().getTicks() * ppb / TimePos::ticksPerBar(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user