From d6cf417a4d07c3f7c36bbfe881d5883c3a68aba0 Mon Sep 17 00:00:00 2001 From: superpaik <68785450+superpaik@users.noreply.github.com> Date: Thu, 24 Aug 2023 18:02:26 +0200 Subject: [PATCH] Change zoom in SongEditor to a Slider Zoom (#6664) Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com> Co-authored-by: Alex --- data/themes/classic/horizontal_slider.png | Bin 0 -> 1444 bytes data/themes/classic/style.css | 19 ++ data/themes/default/horizontal_slider.png | Bin 0 -> 1065 bytes data/themes/default/style.css | 19 ++ include/SongEditor.h | 17 +- src/gui/clips/ClipView.cpp | 9 +- src/gui/editors/SongEditor.cpp | 239 ++++++++++++---------- src/gui/editors/TimeLineWidget.cpp | 22 +- 8 files changed, 198 insertions(+), 127 deletions(-) create mode 100644 data/themes/classic/horizontal_slider.png create mode 100644 data/themes/default/horizontal_slider.png diff --git a/data/themes/classic/horizontal_slider.png b/data/themes/classic/horizontal_slider.png new file mode 100644 index 0000000000000000000000000000000000000000..49d16b9d869e01d2380a90b5615d9cc6d2d10fb0 GIT binary patch literal 1444 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr|-8<6aKa#jsUNtU=qlmzFem6RtIr7}3Cer{{GxPyLrY6bkQqisxQ#zd*q`*i1nqJTosPzr0uz ztlrnx$}_LHBrz{J)zigR321^|W@d_&p`oR#i;*(J3ovn(~mttdZN0qkX~Ox$j9!f75< zZwhX=IOEi-4|I$^C}NQ!8YToxJs>7L*#bH6grAxROzlO$WZnEmY$^i-lZ2;>V@SoV zmf+oew*mxY<7Y3=$WUt8BC=3vnvzKV;rbSZ9}H4I`j^}?Q3!0fbm78>U(B=Cw7gi< z+rs3!X;Fl-0E+;B^IYrXb%x#(8E+S-_nkj8w_2w$cm6|rwWpsey(cYMy&!W|fsNcj z1D>esufOVZHC>v2DM5zEOOB7-Yu)v1rf*fYQQ8&BLd^T`zc)~l;1oNp+L6U0drX3L z*Im6OL7EJu+7cR*ISrz^qb^wXj*HC4Yj-|Yy#6+5pca?!lI zJzu(xKVGQtZAGTkiuWP24)6v9if}!$IQ7&>b)ulTN>A07s=WnPa}{Qv4Jt5^irrc? z^YLogIEVGelqb#gV-E>!t+1)9i`*r*D71qvGmuN z2C;uX&pREjo1`CgnDrFb`moikoi0rGKFQ@OSR~x?Q4m;gplo-m*HWi_nKS=n#+{!S zgqd~@CT#_BK)kuMo0Rp&*QJQnm@9$ZoLr%x%eaKW_!7<`*!r_zN0-$o!)78&q Iol`;+08;c5761SM literal 0 HcmV?d00001 diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 2880fe661..d1f4d0588 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -418,6 +418,25 @@ lmms--gui--AutomatableSlider::handle:vertical { margin: -4px -12px -2px; } +/* main horizontal sliders (zoom) */ + +lmms--gui--AutomatableSlider::groove:horizontal { + background: rgba(0,0,0, 128); + border: 1px inset rgba(100,100,100, 64); + border-radius: 2px; + height: 2px; + margin: 2px; +} + +lmms--gui--AutomatableSlider::handle:horizontal { + background: none; + border-image: url(resources:horizontal_slider.png); + width: 10px; + height: 26px; + border-radius: 2px; + margin: -12px -2px; +} + /* about dialog */ QTabWidget, QTabWidget QWidget { background: #5b6571; diff --git a/data/themes/default/horizontal_slider.png b/data/themes/default/horizontal_slider.png new file mode 100644 index 0000000000000000000000000000000000000000..24f6098e517df6a8ae5c0372b117241437e2f4bb GIT binary patch literal 1065 zcmah|O-K|`9G_Z{TD7Q4W>UileNemevAg5Ur&gz*_o#fI`gKPx9w__ zU?|oh^ddnN9V#OFIw~G4>e3ZS(Ht+OBytTs)q>{O&hZbqPeALtJ(lSWDfKhR+RcSH&2m<9;MDiQcTK@gMOoJ z*a6+c9T{zSKofPUw2EPwWfeIVQaFVZ7*1ftgeWT&Zqjm*YH6UtH8!}) zrd%oR02M(e1L0t$dtLnyLAM{;WW1Xv51%nC9TwapUTMopfn%HpdcuJwS*nd>{1xBR zo`|u0f)5K}xm8rK`k0_3;%rEeg*ekHa1pA^)&G(Af4MXkLwk+=qtTTsJUyPdKDPL< zKKQ`G)9&E0zN)s*;U{r3DaSI!_qkuIt1Z4$#Dlk06P=?oS*Gp7_^vyXQ&Wp~CMRb0 zHqi%s)zwFRo%f^{Z)SJa3F2(s^_5j1jC_B2U~GAuPlAtbNTku zZP{DfZ@4}FsV#T?XYZTT*Jo!_`LPA!^w`Ly<^96g$VBGHg-;LfjX&vJ{<-LzZv5 m_zoomLevels; - bool m_scrollBack; bool m_smoothScroll; @@ -158,14 +158,14 @@ private: QPoint m_mousePos; int m_rubberBandStartTrackview; TimePos m_rubberbandStartTimePos; - int m_currentZoomingValue; + int m_rubberbandPixelsPerBar; //!< pixels per bar when selection starts int m_trackHeadWidth; bool m_selectRegion; friend class SongEditorWindow; signals: - void zoomingValueChanged( float ); + void pixelsPerBarChanged(float); } ; @@ -213,7 +213,7 @@ private: QAction* m_selectModeAction; QAction* m_crtlAction; - ComboBox * m_zoomingComboBox; + AutomatableSlider * m_zoomingSlider; ComboBox * m_snappingComboBox; QLabel* m_snapSizeLabel; @@ -221,7 +221,6 @@ private: QAction* m_removeBarAction; }; - } // namespace gui } // namespace lmms diff --git a/src/gui/clips/ClipView.cpp b/src/gui/clips/ClipView.cpp index 8a190e2a7..b78605906 100644 --- a/src/gui/clips/ClipView.cpp +++ b/src/gui/clips/ClipView.cpp @@ -125,7 +125,7 @@ ClipView::ClipView( Clip * clip, connect( m_clip, SIGNAL(lengthChanged()), this, SLOT(updateLength())); - connect( getGUI()->songEditor()->m_editor->zoomingModel(), SIGNAL(dataChanged()), this, SLOT(updateLength())); + connect(getGUI()->songEditor()->m_editor, &SongEditor::pixelsPerBarChanged, this, &ClipView::updateLength); connect( m_clip, SIGNAL(positionChanged()), this, SLOT(updatePosition())); connect( m_clip, SIGNAL(destroyedClip()), this, SLOT(close())); @@ -314,10 +314,9 @@ void ClipView::updateLength() } else { - setFixedWidth( - static_cast( m_clip->length() * pixelsPerBar() / - TimePos::ticksPerBar() ) + 1 /*+ - BORDER_WIDTH * 2-1*/ ); + // this std::max function is needed for clips that do not start or end on the beat, otherwise, they "disappear" when zooming to min + // 3 is the minimun width needed to make a clip visible + setFixedWidth(std::max(static_cast(m_clip->length() * pixelsPerBar() / TimePos::ticksPerBar() + 1), 3)); } m_trackView->trackContainerView()->update(); } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 3e62cc238..939c1fdf4 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -24,11 +24,14 @@ #include "SongEditor.h" +#include + #include #include #include #include #include +#include #include #include "ActionGroup.h" @@ -57,14 +60,24 @@ namespace lmms::gui { +namespace +{ + +constexpr int MIN_PIXELS_PER_BAR = 2; +constexpr int MAX_PIXELS_PER_BAR = 400; +constexpr int ZOOM_STEPS = 200; + +constexpr std::array SNAP_SIZES{8.f, 4.f, 2.f, 1.f, 1/2.f, 1/4.f, 1/8.f, 1/16.f}; +constexpr std::array PROPORTIONAL_SNAP_SIZES{64.f, 32.f, 16.f, 8.f, 4.f, 2.f, 1.f, 1/2.f, 1/4.f, 1/8.f, 1/16.f, 1/32.f, 1/64.f}; + +} + -const QVector SongEditor::m_zoomLevels = - { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f }; SongEditor::SongEditor( Song * song ) : TrackContainerView( song ), m_song( song ), - m_zoomingModel(new ComboBoxModel()), + m_zoomingModel(new IntModel(calculateZoomSliderValue(DEFAULT_PIXELS_PER_BAR), 0, ZOOM_STEPS, nullptr, tr("Zoom"))), m_snappingModel(new ComboBoxModel()), m_proportionalSnap( false ), m_scrollBack( false ), @@ -75,7 +88,7 @@ SongEditor::SongEditor( Song * song ) : m_mousePos(), m_rubberBandStartTrackview(0), m_rubberbandStartTimePos(0), - m_currentZoomingValue(m_zoomingModel->value()), + m_rubberbandPixelsPerBar(DEFAULT_PIXELS_PER_BAR), m_trackHeadWidth(ConfigManager::inst()->value("ui", "compacttrackbuttons").toInt()==1 ? DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH), @@ -83,6 +96,7 @@ SongEditor::SongEditor( Song * song ) : { m_zoomingModel->setParent(this); m_snappingModel->setParent(this); + m_timeLine = new TimeLineWidget( m_trackHeadWidth, 32, pixelsPerBar(), m_song->m_playPos[Song::Mode_PlaySong], @@ -103,12 +117,15 @@ SongEditor::SongEditor( Song * song ) : m_positionLine = new PositionLine(this); static_cast( layout() )->insertWidget( 1, m_timeLine ); - + connect( m_song, SIGNAL(playbackStateChanged()), m_positionLine, SLOT(update())); - connect( this, SIGNAL(zoomingValueChanged(float)), - m_positionLine, SLOT(zoomChange(float))); - + + // When zoom changes, update position line + // But we must convert pixels per bar to a zoom factor where 1.0 is 100% + connect(this, &SongEditor::pixelsPerBarChanged, m_positionLine, + [this]() { m_positionLine->zoomChange(pixelsPerBar() / float(DEFAULT_PIXELS_PER_BAR)); }); + // Ensure loop markers snap to same increments as clips. Zoom & proportional // snap changes are handled in zoomingChanged() and toggleProportionalSnap() connect(m_snappingModel, &ComboBoxModel::dataChanged, @@ -171,8 +188,8 @@ SongEditor::SongEditor( Song * song ) : SLOT(hideMasterVolumeFloat())); m_mvsStatus = new TextFloat; - m_mvsStatus->setTitle( tr( "Master volume" ) ); - m_mvsStatus->setPixmap( embed::getIconPixmap( "master_volume" ) ); + m_mvsStatus->setTitle(tr("Master volume")); + m_mvsStatus->setPixmap(embed::getIconPixmap("master_volume")); getGUI()->mainWindow()->addWidgetToToolBar( master_vol_lbl ); getGUI()->mainWindow()->addWidgetToToolBar( m_masterVolumeSlider ); @@ -240,33 +257,23 @@ SongEditor::SongEditor( Song * song ) : connect(contentWidget()->verticalScrollBar(), SIGNAL(valueChanged(int)),this, SLOT(updateRubberband())); connect(m_timeLine, SIGNAL(selectionFinished()), this, SLOT(stopSelectRegion())); + //zoom connects + connect(m_zoomingModel, SIGNAL(dataChanged()), this, SLOT(zoomingChanged())); - //Set up zooming model - for( float const & zoomLevel : m_zoomLevels ) + // Set up snapping model + for (float bars : SNAP_SIZES) { - m_zoomingModel->addItem( QString( "%1\%" ).arg( zoomLevel * 100 ) ); - } - m_zoomingModel->setInitValue( - m_zoomingModel->findText( "100%" ) ); - connect( m_zoomingModel, SIGNAL(dataChanged()), - this, SLOT(zoomingChanged())); - connect( m_zoomingModel, SIGNAL(dataChanged()), - m_positionLine, SLOT(update())); - - //Set up snapping model, 2^i - for ( int i = 3; i >= -4; i-- ) - { - if ( i > 0 ) + if (bars > 1.0f) { - m_snappingModel->addItem( QString( "%1 Bars").arg( 1 << i ) ); + m_snappingModel->addItem(QString("%1 Bars").arg(bars)); } - else if ( i == 0 ) + else if (bars == 1.0f) { m_snappingModel->addItem( "1 Bar" ); } else { - m_snappingModel->addItem( QString( "1/%1 Bar" ).arg( 1 << (-i) ) ); + m_snappingModel->addItem(QString("1/%1 Bar").arg(1 / bars)); } } m_snappingModel->setInitValue( m_snappingModel->findText( "1 Bar" ) ); @@ -291,42 +298,40 @@ void SongEditor::loadSettings( const QDomElement& element ) +/*! \brief Return grid size as number of bars */ float SongEditor::getSnapSize() const { - // 1 Bar is the third value in the snapping dropdown - int val = -m_snappingModel->value() + 3; + float snapSize = SNAP_SIZES[m_snappingModel->value()]; + // If proportional snap is on, we snap to finer values when zoomed in if (m_proportionalSnap) { - val = val - m_zoomingModel->value() + 3; + // Finds the closest available snap size + const float optimalSize = snapSize * DEFAULT_PIXELS_PER_BAR / pixelsPerBar(); + return *std::min_element(PROPORTIONAL_SNAP_SIZES.begin(), PROPORTIONAL_SNAP_SIZES.end(), [optimalSize](float a, float b) + { + return std::abs(a - optimalSize) < std::abs(b - optimalSize); + }); } - val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. - if ( val >= 0 ){ - return 1 << val; - } - else { - return 1.0 / ( 1 << -val ); - } + return snapSize; } QString SongEditor::getSnapSizeString() const { - int val = -m_snappingModel->value() + 3; - val = val - m_zoomingModel->value() + 3; - val = std::max(val, -6); // -6 gives 1/64th bar snapping. Lower values cause crashing. + float bars = getSnapSize(); - if ( val >= 0 ){ - int bars = 1 << val; - if ( bars == 1 ) { return QString("1 Bar"); } - else - { - return QString( "%1 Bars" ).arg(bars); - } + if (bars < 1) + { + return QString(tr("1/%1 Bar")).arg(round(1 / bars)); } - else { - int div = ( 1 << -val ); - return QString( "1/%1 Bar" ).arg(div); + else if (bars >= 2) + { + return QString(tr("%1 Bars")).arg(bars); + } + else + { + return QString("1 Bar"); } } @@ -367,7 +372,7 @@ void SongEditor::selectRegionFromPixels(int xStart, int xEnd) //we save the position of scrollbars, mouse position and zooming level m_origin = QPoint(xStart, 0); m_scrollPos = QPoint(m_leftRightScroll->value(), contentWidget()->verticalScrollBar()->value()); - m_currentZoomingValue = zoomingModel()->value(); + m_rubberbandPixelsPerBar = pixelsPerBar(); //calculate the song position where the mouse was clicked m_rubberbandStartTimePos = TimePos((xStart - m_trackHeadWidth) @@ -399,10 +404,9 @@ void SongEditor::updateRubberband() int originX = m_origin.x(); //take care of the zooming - if (m_currentZoomingValue != m_zoomingModel->value()) + if (m_rubberbandPixelsPerBar != pixelsPerBar()) { - originX = m_trackHeadWidth + (originX - m_trackHeadWidth) - * m_zoomLevels[m_zoomingModel->value()] / m_zoomLevels[m_currentZoomingValue]; + originX = m_trackHeadWidth + (originX - m_trackHeadWidth) * pixelsPerBar() / m_rubberbandPixelsPerBar; } //take care of the scrollbar position @@ -524,9 +528,13 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) { selectAllClips( false ); } + else if (ke->key() == Qt::Key_0 && ke->modifiers() & Qt::ControlModifier) + { + m_zoomingModel->reset(); + } else { - QWidget::keyPressEvent( ke ); + QWidget::keyPressEvent(ke); } } @@ -535,35 +543,24 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) void SongEditor::wheelEvent( QWheelEvent * we ) { - if( we->modifiers() & Qt::ControlModifier ) + if ((we->modifiers() & Qt::ControlModifier) && (position(we).x() > m_trackHeadWidth)) { - int z = m_zoomingModel->value(); - - if(we->angleDelta().y() > 0) - { - z++; - } - else if(we->angleDelta().y() < 0) - { - z--; - } - z = qBound( 0, z, m_zoomingModel->size() - 1 ); - - int x = position(we).x() - m_trackHeadWidth; // bar based on the mouse x-position where the scroll wheel was used int bar = x / pixelsPerBar(); - // what would be the bar in the new zoom level on the very same mouse x - int newBar = x / DEFAULT_PIXELS_PER_BAR / m_zoomLevels[z]; - // scroll so the bar "selected" by the mouse x doesn't move on the screen + + // move zoom slider (pixelsPerBar will change automatically) + int step = we->modifiers() & Qt::ShiftModifier ? 1 : 5; + // when Alt is pressed, wheelEvent returns delta for x coordinate (mimics horizontal mouse wheel) + 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(x / pixelsPerBar()); m_leftRightScroll->setValue(m_leftRightScroll->value() + bar - newBar); - // update combobox with zooming-factor - m_zoomingModel->setValue( z ); - // update timeline - m_song->m_playPos[Song::Mode_PlaySong].m_timeLine-> - setPixelsPerBar( pixelsPerBar() ); + m_song->m_playPos[Song::Mode_PlaySong].m_timeLine->setPixelsPerBar(pixelsPerBar()); // and make sure, all Clip's are resized and relocated realignTracks(); } @@ -612,7 +609,7 @@ void SongEditor::mousePressEvent(QMouseEvent *me) //we save the position of scrollbars, mouse position and zooming level m_scrollPos = QPoint(m_leftRightScroll->value(), contentWidget()->verticalScrollBar()->value()); m_origin = contentWidget()->mapFromParent(QPoint(me->pos().x(), me->pos().y())); - m_currentZoomingValue = zoomingModel()->value(); + m_rubberbandPixelsPerBar = pixelsPerBar(); //paint the rubberband rubberBand()->setEnabled(true); @@ -655,12 +652,12 @@ void SongEditor::setMasterVolume( int new_val ) { updateMasterVolumeFloat( new_val ); - if( !m_mvsStatus->isVisible() && !m_song->m_loadingProject + if (!m_mvsStatus->isVisible() && !m_song->m_loadingProject && m_masterVolumeSlider->showStatus() ) { - m_mvsStatus->moveGlobal( m_masterVolumeSlider, + m_mvsStatus->moveGlobal(m_masterVolumeSlider, QPoint( m_masterVolumeSlider->width() + 2, -2 ) ); - m_mvsStatus->setVisibilityTimeOut( 1000 ); + m_mvsStatus->setVisibilityTimeOut(1000); } Engine::audioEngine()->setMasterGain( new_val / 100.0f ); } @@ -670,7 +667,7 @@ void SongEditor::setMasterVolume( int new_val ) void SongEditor::showMasterVolumeFloat( void ) { - m_mvsStatus->moveGlobal( m_masterVolumeSlider, + m_mvsStatus->moveGlobal(m_masterVolumeSlider, QPoint( m_masterVolumeSlider->width() + 2, -2 ) ); m_mvsStatus->show(); updateMasterVolumeFloat( m_song->m_masterVolumeModel.value() ); @@ -681,7 +678,7 @@ void SongEditor::showMasterVolumeFloat( void ) void SongEditor::updateMasterVolumeFloat( int new_val ) { - m_mvsStatus->setText( tr( "Value: %1%" ).arg( new_val ) ); + m_mvsStatus->setText(tr("Value: %1%").arg(new_val)); } @@ -837,17 +834,50 @@ void SongEditor::updatePositionLine() +//! Convert zoom slider's value to bar width in pixels +int SongEditor::calculatePixelsPerBar() const +{ + // What we need to raise 2 by to get MIN_PIXELS_PER_BAR and MAX_PIXELS_PER_BAR + static const double minExp = std::log2(MIN_PIXELS_PER_BAR); + static const double maxExp = std::log2(MAX_PIXELS_PER_BAR); + static const double stepsInv = 1 / static_cast(ZOOM_STEPS) * (maxExp - minExp); + double exponent = m_zoomingModel->value() * stepsInv + minExp; + + double ppb = std::exp2(exponent); + + return static_cast(std::round(ppb)); +} + + + + +//! Convert bar width in pixels to zoom slider value +int SongEditor::calculateZoomSliderValue(int pixelsPerBar) const +{ + // What we need to raise 2 by to get MIN_PIXELS_PER_BAR and MAX_PIXELS_PER_BAR + static const double minExp = std::log2(MIN_PIXELS_PER_BAR); + static const double maxExp = std::log2(MAX_PIXELS_PER_BAR); + double exponent = std::log2(pixelsPerBar); + + double sliderValue = (exponent - minExp) / (maxExp - minExp) * ZOOM_STEPS; + + return static_cast(std::round(sliderValue)); +} + + + + void SongEditor::zoomingChanged() { - setPixelsPerBar( m_zoomLevels[m_zoomingModel->value()] * DEFAULT_PIXELS_PER_BAR ); + int ppb = calculatePixelsPerBar(); + setPixelsPerBar(ppb); - m_song->m_playPos[Song::Mode_PlaySong].m_timeLine-> - setPixelsPerBar( pixelsPerBar() ); + m_song->m_playPos[Song::Mode_PlaySong].m_timeLine->setPixelsPerBar(ppb); realignTracks(); updateRubberband(); m_timeLine->setSnapSize(getSnapSize()); - - emit zoomingValueChanged( m_zoomLevels[m_zoomingModel->value()] ); + + emit pixelsPerBarChanged(ppb); } @@ -899,14 +929,6 @@ int SongEditor::indexOfTrackView(const TrackView *tv) -ComboBoxModel *SongEditor::zoomingModel() const -{ - return m_zoomingModel; -} - - - - ComboBoxModel *SongEditor::snappingModel() const { return m_snappingModel; @@ -991,16 +1013,19 @@ SongEditorWindow::SongEditorWindow(Song* song) : auto zoom_lbl = new QLabel(m_toolBar); zoom_lbl->setPixmap( embed::getIconPixmap( "zoom" ) ); - //Set up zooming-stuff - m_zoomingComboBox = new ComboBox( m_toolBar ); - m_zoomingComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); - 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())); + // Set slider zoom + m_zoomingSlider = new AutomatableSlider(m_toolBar, tr("Zoom")); + m_zoomingSlider->setModel(m_editor->m_zoomingModel); + m_zoomingSlider->setOrientation(Qt::Horizontal); + m_zoomingSlider->setPageStep(1); + m_zoomingSlider->setFocusPolicy(Qt::NoFocus); + m_zoomingSlider->setFixedSize(100, 26); + m_zoomingSlider->setToolTip(tr("Zoom")); + m_zoomingSlider->setContextMenuPolicy(Qt::NoContextMenu); + connect(m_editor->m_zoomingModel, SIGNAL(dataChanged()), this, SLOT(updateSnapLabel())); zoomToolBar->addWidget( zoom_lbl ); - zoomToolBar->addWidget( m_zoomingComboBox ); + zoomToolBar->addWidget(m_zoomingSlider); DropToolBar *snapToolBar = addDropToolBarToTop(tr("Snap controls")); auto snap_lbl = new QLabel(m_toolBar); @@ -1034,7 +1059,7 @@ SongEditorWindow::SongEditorWindow(Song* song) : QSize SongEditorWindow::sizeHint() const { - return {720, 300}; + return {900, 300}; } void SongEditorWindow::updateSnapLabel(){ @@ -1140,3 +1165,5 @@ void SongEditorWindow::adjustUiAfterProjectLoad() } // namespace lmms::gui + + diff --git a/src/gui/editors/TimeLineWidget.cpp b/src/gui/editors/TimeLineWidget.cpp index 12b6a11f5..b051fa79b 100644 --- a/src/gui/editors/TimeLineWidget.cpp +++ b/src/gui/editors/TimeLineWidget.cpp @@ -22,23 +22,29 @@ * */ +#include "TimeLineWidget.h" + +#include #include -#include #include #include +#include #include - -#include "TimeLineWidget.h" #include "embed.h" -#include "NStateButton.h" #include "GuiApplication.h" +#include "NStateButton.h" #include "TextFloat.h" namespace lmms::gui { +namespace +{ + constexpr int MIN_BAR_LABEL_DISTANCE = 35; +} + QPixmap * TimeLineWidget::s_posMarkerPixmap = nullptr; @@ -270,12 +276,14 @@ void TimeLineWidget::paintEvent( QPaintEvent * ) int const x = m_xOffset + s_posMarkerPixmap->width() / 2 - ( ( static_cast( m_begin * m_ppb ) / TimePos::ticksPerBar() ) % static_cast( m_ppb ) ); + // Double the interval between bar numbers until they are far enough appart + int barLabelInterval = 1; + while (barLabelInterval * m_ppb < MIN_BAR_LABEL_DISTANCE) { barLabelInterval *= 2; } + for( int i = 0; x + i * m_ppb < width(); ++i ) { ++barNumber; - if( ( barNumber - 1 ) % - qMax( 1, qRound( 1.0f / 3.0f * - TimePos::ticksPerBar() / m_ppb ) ) == 0 ) + if ((barNumber - 1) % barLabelInterval == 0) { const int cx = x + qRound( i * m_ppb ); p.setPen( barLineColor );