From a81666a9f55420828a12abf787db693222da885f Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sun, 18 Feb 2024 21:22:22 +0100 Subject: [PATCH] Track resizing behavior (#7114) * Simplify TrackLabelButton Remove the dependency to `Instrument` and `InstrumentTrack` from `TrackLabelButton`. The icon of an `InstrumentTrackView` is now determined in the class `InstrumentTrackView` itself using the new static method `determinePixmap`. This enables the removal of the overridden `paintEvent` method from `TrackLabelButton`. It was also attempted to keep a non-static member function version and to use the `InstrumentTrackView`'s model with a cast. However, this did not work because 'setModel' is executed as the very last step in the constructor, i.e. the model is not already set when `determinePixmap` is called. Pulling it to the top is too risky right now. * Add helper method isInCompactMode Add the helper method `isInCompactMode` which knows how to use the `ConfigManager` to determine if the option for compact track buttons is enabled. This removes duplicate code with intricate knowledge of the keys under which compact mode is stored. * Set song as modified when track name changes Extend `Track::setName` to set the song as modified whenever the track name changes. This moves the update into a core class and enables the removal of the dependencies to `Engine` and `Song` from the GUI class `TrackLabelButton`. Also add a check if the name is really changed and only perform the actions if that's the case. To make this work the implementation of `setName` had to be moved from the header into the implementation file. * Keep instrument and sample content at top on resize Keep the content of the instrument and sample track at the top of the widget if the widget is resized. This is also fixes a bug where the `TrackLabelButton` does not react anymore when the size is increased. Technically the layout with the actual widgets is put into another vertical layout with a spacer that consumes all remaining space at the bottom. * Vertical track resizing via mouse wheel Enable to vertically resize tracks using the mouse wheel. Scrolling the mouse wheel over the track view with the control key pressed will increase/decrease the height by one pixel per wheel event. Pressing the shift key will increase/decrease in steps of five pixels. Extract code that can be shared between the existing and the new way to resize the track into the private helper method `resizeToHeight`. * Render beat pattern step buttons at the top Render the step buttons of beat patterns at the top instead of at the bottom so that they stay aligned with the other elements to the left of them (buttons, knobs, etc). Set the y offset to 4 so that the step buttons are vertically aligned with the other elements. The previous calculation lead to a minimum offset of 6 which always made the step buttons look misaligned. Introduce the new static variable `BeatStepButtonOffset` which ensures that the rendering and the evaluation of mouse clicks do not go out of sync. --- include/InstrumentTrackView.h | 2 ++ include/Track.h | 6 +--- include/TrackLabelButton.h | 3 +- include/TrackView.h | 3 ++ src/core/Track.cpp | 15 +++++++++ src/gui/clips/MidiClipView.cpp | 5 +-- src/gui/tracks/InstrumentTrackView.cpp | 32 ++++++++++++++++-- src/gui/tracks/SampleTrackView.cpp | 6 +++- src/gui/tracks/TrackLabelButton.cpp | 46 +++++--------------------- src/gui/tracks/TrackView.cpp | 28 ++++++++++++++-- 10 files changed, 94 insertions(+), 52 deletions(-) diff --git a/include/InstrumentTrackView.h b/include/InstrumentTrackView.h index e89a576e9..c7d524b36 100644 --- a/include/InstrumentTrackView.h +++ b/include/InstrumentTrackView.h @@ -93,6 +93,8 @@ private slots: void handleConfigChange(QString cls, QString attr, QString value); +private: + static QPixmap determinePixmap(InstrumentTrack* instrumentTrack); private: InstrumentTrackWindow * m_window; diff --git a/include/Track.h b/include/Track.h index 248d56b04..1c161984f 100644 --- a/include/Track.h +++ b/include/Track.h @@ -201,11 +201,7 @@ public: BoolModel* getMutedModel(); public slots: - virtual void setName( const QString & newName ) - { - m_name = newName; - emit nameChanged(); - } + virtual void setName(const QString& newName); void setMutedBeforeSolo(const bool muted) { diff --git a/include/TrackLabelButton.h b/include/TrackLabelButton.h index 0d1c6e163..e19fc6be9 100644 --- a/include/TrackLabelButton.h +++ b/include/TrackLabelButton.h @@ -55,9 +55,10 @@ protected: void mousePressEvent( QMouseEvent * _me ) override; void mouseDoubleClickEvent( QMouseEvent * _me ) override; void mouseReleaseEvent( QMouseEvent * _me ) override; - void paintEvent( QPaintEvent * _pe ) override; void resizeEvent( QResizeEvent * _re ) override; +private: + bool isInCompactMode() const; private: TrackView * m_trackView; diff --git a/include/TrackView.h b/include/TrackView.h index f697d9ea8..b2654202b 100644 --- a/include/TrackView.h +++ b/include/TrackView.h @@ -134,9 +134,12 @@ protected: void mousePressEvent( QMouseEvent * me ) override; void mouseMoveEvent( QMouseEvent * me ) override; void mouseReleaseEvent( QMouseEvent * me ) override; + void wheelEvent(QWheelEvent* we) override; void paintEvent( QPaintEvent * pe ) override; void resizeEvent( QResizeEvent * re ) override; +private: + void resizeToHeight(int height); private: enum class Action diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 13c1d6988..6c4ba465e 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -637,4 +637,19 @@ BoolModel *Track::getMutedModel() return &m_mutedModel; } +void Track::setName(const QString& newName) +{ + if (m_name != newName) + { + m_name = newName; + + if (auto song = Engine::getSong()) + { + song->setModified(); + } + + emit nameChanged(); + } +} + } // namespace lmms diff --git a/src/gui/clips/MidiClipView.cpp b/src/gui/clips/MidiClipView.cpp index a9ee1cb40..0a6fece31 100644 --- a/src/gui/clips/MidiClipView.cpp +++ b/src/gui/clips/MidiClipView.cpp @@ -46,6 +46,7 @@ namespace lmms::gui { +constexpr int BeatStepButtonOffset = 4; MidiClipView::MidiClipView( MidiClip* clip, TrackView* parent ) : ClipView( clip, parent ), @@ -246,7 +247,7 @@ void MidiClipView::mousePressEvent( QMouseEvent * _me ) { bool displayPattern = fixedClips() || (pixelsPerBar() >= 96 && m_legacySEPattern); if (_me->button() == Qt::LeftButton && m_clip->m_clipType == MidiClip::Type::BeatClip && displayPattern - && _me->y() > height() - m_stepBtnOff.height()) + && _me->y() > BeatStepButtonOffset && _me->y() < BeatStepButtonOffset + m_stepBtnOff.height()) // when mouse button is pressed in pattern mode @@ -478,7 +479,7 @@ void MidiClipView::paintEvent( QPaintEvent * ) // figure out x and y coordinates for step graphic const int x = BORDER_WIDTH + static_cast(it * w / steps); - const int y = height() - m_stepBtnOff.height() - 1; + const int y = BeatStepButtonOffset; if (n) { diff --git a/src/gui/tracks/InstrumentTrackView.cpp b/src/gui/tracks/InstrumentTrackView.cpp index 12b6227ca..788991ed0 100644 --- a/src/gui/tracks/InstrumentTrackView.cpp +++ b/src/gui/tracks/InstrumentTrackView.cpp @@ -40,6 +40,7 @@ #include "Mixer.h" #include "MixerView.h" #include "GuiApplication.h" +#include "Instrument.h" #include "InstrumentTrack.h" #include "InstrumentTrackWindow.h" #include "MainWindow.h" @@ -62,7 +63,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV m_tlb = new TrackLabelButton( this, getTrackSettingsWidget() ); m_tlb->setCheckable( true ); - m_tlb->setIcon( embed::getIconPixmap( "instrument_track" ) ); + m_tlb->setIcon(determinePixmap(_it)); m_tlb->show(); connect( m_tlb, SIGNAL(toggled(bool)), @@ -142,7 +143,9 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV m_activityIndicator->setFixedSize(8, 28); m_activityIndicator->show(); - auto layout = new QHBoxLayout(getTrackSettingsWidget()); + auto masterLayout = new QVBoxLayout(getTrackSettingsWidget()); + masterLayout->setContentsMargins(0, 1, 0, 0); + auto layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(m_tlb); @@ -150,6 +153,8 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV layout->addWidget(m_activityIndicator); layout->addWidget(m_volumeKnob); layout->addWidget(m_panningKnob); + masterLayout->addLayout(layout); + masterLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); connect( m_activityIndicator, SIGNAL(pressed()), this, SLOT(activityIndicatorPressed())); @@ -393,4 +398,27 @@ QMenu * InstrumentTrackView::createMixerMenu(QString title, QString newMixerLabe } +QPixmap InstrumentTrackView::determinePixmap(InstrumentTrack* instrumentTrack) +{ + if (instrumentTrack) + { + Instrument* instrument = instrumentTrack->instrument(); + + if (instrument && instrument->descriptor()) + { + const PixmapLoader* pl = instrument->key().isValid() + ? instrument->key().logo() + : instrument->descriptor()->logo; + + if (pl) + { + return pl->pixmap(); + } + } + } + + return embed::getIconPixmap("instrument_track"); +} + + } // namespace lmms::gui diff --git a/src/gui/tracks/SampleTrackView.cpp b/src/gui/tracks/SampleTrackView.cpp index 45a695d11..8475f7fa9 100644 --- a/src/gui/tracks/SampleTrackView.cpp +++ b/src/gui/tracks/SampleTrackView.cpp @@ -86,7 +86,9 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : m_activityIndicator->setFixedSize(8, 28); m_activityIndicator->show(); - auto layout = new QHBoxLayout(getTrackSettingsWidget()); + auto masterLayout = new QVBoxLayout(getTrackSettingsWidget()); + masterLayout->setContentsMargins(0, 1, 0, 0); + auto layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(m_tlb); @@ -94,6 +96,8 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : layout->addWidget(m_activityIndicator); layout->addWidget(m_volumeKnob); layout->addWidget(m_panningKnob); + masterLayout->addLayout(layout); + masterLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); connect(_t, SIGNAL(playingChanged()), this, SLOT(updateIndicator())); diff --git a/src/gui/tracks/TrackLabelButton.cpp b/src/gui/tracks/TrackLabelButton.cpp index 2a50a4aa2..087edba3d 100644 --- a/src/gui/tracks/TrackLabelButton.cpp +++ b/src/gui/tracks/TrackLabelButton.cpp @@ -30,13 +30,10 @@ #include "ConfigManager.h" #include "embed.h" -#include "Engine.h" -#include "Instrument.h" -#include "InstrumentTrack.h" #include "RenameDialog.h" -#include "Song.h" #include "TrackRenameLineEdit.h" #include "TrackView.h" +#include "Track.h" namespace lmms::gui { @@ -53,7 +50,7 @@ TrackLabelButton::TrackLabelButton( TrackView * _tv, QWidget * _parent ) : m_renameLineEdit = new TrackRenameLineEdit( this ); m_renameLineEdit->hide(); - if( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() ) + if (isInCompactMode()) { setFixedSize( 32, 29 ); } @@ -77,7 +74,7 @@ TrackLabelButton::TrackLabelButton( TrackView * _tv, QWidget * _parent ) : void TrackLabelButton::rename() { - if( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() ) + if (isInCompactMode()) { QString txt = m_trackView->getTrack()->name(); RenameDialog renameDlg( txt ); @@ -85,7 +82,6 @@ void TrackLabelButton::rename() if( txt != text() ) { m_trackView->getTrack()->setName( txt ); - Engine::getSong()->setModified(); } } else @@ -103,7 +99,7 @@ void TrackLabelButton::rename() void TrackLabelButton::renameFinished() { - if( !( ConfigManager::inst()->value( "ui", "compacttrackbuttons" ).toInt() ) ) + if (!isInCompactMode()) { m_renameLineEdit->clearFocus(); m_renameLineEdit->hide(); @@ -113,7 +109,6 @@ void TrackLabelButton::renameFinished() { setText( elideName( m_renameLineEdit->text() ) ); m_trackView->getTrack()->setName( m_renameLineEdit->text() ); - Engine::getSong()->setModified(); } } } @@ -185,35 +180,6 @@ void TrackLabelButton::mouseReleaseEvent( QMouseEvent *_me ) -void TrackLabelButton::paintEvent( QPaintEvent * _pe ) -{ - if( m_trackView->getTrack()->type() == Track::Type::Instrument ) - { - auto it = dynamic_cast(m_trackView->getTrack()); - const PixmapLoader * pl; - auto get_logo = [](InstrumentTrack* it) -> const PixmapLoader* - { - return it->instrument()->key().isValid() - ? it->instrument()->key().logo() - : it->instrument()->descriptor()->logo; - }; - if( it && it->instrument() && - it->instrument()->descriptor() && - ( pl = get_logo(it) ) ) - { - if( pl->pixmapName() != m_iconName ) - { - m_iconName = pl->pixmapName(); - setIcon( pl->pixmap() ); - } - } - } - QToolButton::paintEvent( _pe ); -} - - - - void TrackLabelButton::resizeEvent(QResizeEvent *_re) { setText( elideName( m_trackView->getTrack()->displayName() ) ); @@ -237,5 +203,9 @@ QString TrackLabelButton::elideName( const QString &name ) return elidedName; } +bool TrackLabelButton::isInCompactMode() const +{ + return ConfigManager::inst()->value("ui", "compacttrackbuttons").toInt(); +} } // namespace lmms::gui diff --git a/src/gui/tracks/TrackView.cpp b/src/gui/tracks/TrackView.cpp index 426be7e36..08ad01c9c 100644 --- a/src/gui/tracks/TrackView.cpp +++ b/src/gui/tracks/TrackView.cpp @@ -364,9 +364,7 @@ void TrackView::mouseMoveEvent( QMouseEvent * me ) } else if( m_action == Action::Resize ) { - setFixedHeight( qMax( me->y(), MINIMAL_TRACK_HEIGHT ) ); - m_trackContainerView->realignTracks(); - m_track->setHeight( height() ); + resizeToHeight(me->y()); } if( height() < DEFAULT_TRACK_HEIGHT ) @@ -393,6 +391,22 @@ void TrackView::mouseReleaseEvent( QMouseEvent * me ) QWidget::mouseReleaseEvent( me ); } +void TrackView::wheelEvent(QWheelEvent* we) +{ + we->accept(); + + const int deltaY = we->angleDelta().y(); + int const direction = deltaY < 0 ? -1 : 1; + + auto const modKeys = we->modifiers(); + int stepSize = modKeys == Qt::ControlModifier ? 1 : modKeys == Qt::ShiftModifier ? 5 : 0; + + if (stepSize != 0) + { + resizeToHeight(height() + stepSize * direction); + } +} + @@ -445,4 +459,12 @@ void TrackView::setIndicatorMute(FadeButton* indicator, bool muted) } +void TrackView::resizeToHeight(int h) +{ + setFixedHeight(qMax(h, MINIMAL_TRACK_HEIGHT)); + m_trackContainerView->realignTracks(); + m_track->setHeight(height()); +} + + } // namespace lmms::gui