diff --git a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml
index 5ce8c9ae3a1..b9d10873f59 100644
--- a/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml
+++ b/res/controllers/Hercules_DJControl_Inpulse_200.midi.xml
@@ -1107,6 +1107,18 @@
+
+
+
+ [Library]
+ ScrollVertical
+ Scroll Vertical (SHIFT + Browser Knob)
+ 0xB3
+ 0x01
+
+
+
+
diff --git a/src/library/trackset/crate/cratetablemodel.cpp b/src/library/trackset/crate/cratetablemodel.cpp
index 60eb14eed34..28388f4bfb1 100644
--- a/src/library/trackset/crate/cratetablemodel.cpp
+++ b/src/library/trackset/crate/cratetablemodel.cpp
@@ -168,6 +168,17 @@ int CrateTableModel::addTracks(
return trackIds.size();
}
+bool CrateTableModel::isLocked() {
+ Crate crate;
+ if (!m_pTrackCollectionManager->internalCollection()
+ ->crates()
+ .readCrateById(m_selectedCrate, &crate)) {
+ qWarning() << "Failed to read create" << m_selectedCrate;
+ return false;
+ }
+ return crate.isLocked();
+}
+
void CrateTableModel::removeTracks(const QModelIndexList& indices) {
VERIFY_OR_DEBUG_ASSERT(m_selectedCrate.isValid()) {
return;
diff --git a/src/library/trackset/crate/cratetablemodel.h b/src/library/trackset/crate/cratetablemodel.h
index 32760e32fb4..fed1f1d4dc3 100644
--- a/src/library/trackset/crate/cratetablemodel.h
+++ b/src/library/trackset/crate/cratetablemodel.h
@@ -20,6 +20,7 @@ class CrateTableModel final : public TrackSetTableModel {
void removeTracks(const QModelIndexList& indices) final;
/// Returns the number of unsuccessful additions.
int addTracks(const QModelIndex& index, const QList& locations) final;
+ bool isLocked() final;
Capabilities getCapabilities() const final;
QString modelKey(bool noSearch) const override;
diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp
index 0332b90fe4b..fff5254d98f 100644
--- a/src/widget/wtracktableview.cpp
+++ b/src/widget/wtracktableview.cpp
@@ -904,9 +904,13 @@ void WTrackTableView::hideOrRemoveSelectedTracks() {
}
TrackModel::Capability cap;
+ // Hide is the primary action if allowed. Else we test for remove capability
if (pTrackModel->hasCapabilities(TrackModel::Capability::Hide)) {
cap = TrackModel::Capability::Hide;
- } else if (pTrackModel->hasCapabilities(TrackModel::Capability::Remove)) {
+ } else if (pTrackModel->isLocked()) { // Locked playlists and crates
+ return;
+ }
+ if (pTrackModel->hasCapabilities(TrackModel::Capability::Remove)) {
cap = TrackModel::Capability::Remove;
} else if (pTrackModel->hasCapabilities(TrackModel::Capability::RemoveCrate)) {
cap = TrackModel::Capability::RemoveCrate;