Skip to content

Commit

Permalink
Merge pull request #4567 from Holzhaus/qml-library-improvements
Browse files Browse the repository at this point in the history
QML: Library Improvements
  • Loading branch information
Swiftb0y authored Jan 14, 2022
2 parents 7819ed7 + a0f982b commit f1c7217
Show file tree
Hide file tree
Showing 16 changed files with 508 additions and 149 deletions.
14 changes: 14 additions & 0 deletions res/qml/FocusedWidgetControl.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Mixxx 0.1 as Mixxx

Mixxx.ControlProxy {

enum WidgetKind {
None,
Searchbar,
Sidebar,
LibraryView
}

group: "[Library]"
key: "focused_widget"
}
91 changes: 85 additions & 6 deletions res/qml/Library.qml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "." as Skin
import Mixxx 0.1 as Mixxx
import QtQml.Models 2.12
import QtQuick 2.12
import "Theme"

Expand All @@ -8,22 +9,89 @@ Item {
color: Theme.deckBackgroundColor
anchors.fill: parent

LibraryControl {
id: libraryControl

onMoveVertical: listView.moveSelectionVertical(offset)
onLoadSelectedTrack: listView.loadSelectedTrack(group, play)
onLoadSelectedTrackIntoNextAvailableDeck: listView.loadSelectedTrackIntoNextAvailableDeck(play)
onFocusWidgetChanged: {
switch (focusWidget) {
case FocusedWidgetControl.WidgetKind.LibraryView:
listView.forceActiveFocus();
break;
}
}
}

ListView {
id: listView

function moveSelectionVertical(value) {
if (value == 0)
return ;

const rowCount = model.rowCount();
if (rowCount == 0)
return ;

currentIndex = Mixxx.MathUtils.positiveModulo(currentIndex + value, rowCount);
}

function loadSelectedTrackIntoNextAvailableDeck(play) {
const url = model.get(currentIndex).fileUrl;
if (!url)
return ;

Mixxx.PlayerManager.loadLocationUrlIntoNextAvailableDeck(url, play);
}

function loadSelectedTrack(group, play) {
const url = model.get(currentIndex).fileUrl;
if (!url)
return ;

const player = Mixxx.PlayerManager.getPlayer(group);
if (!player)
return ;

player.loadTrackFromLocationUrl(url, play);
}

anchors.fill: parent
anchors.margins: 10
clip: true
keyNavigationWraps: true
highlightMoveDuration: 250
highlightResizeDuration: 50
model: Mixxx.Library.model
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
listView.loadSelectedTrackIntoNextAvailableDeck(false);
break;
}
}

delegate: Item {
id: itemDelegate

implicitWidth: 300
implicitWidth: listView.width
implicitHeight: 30

Text {
anchors.fill: parent
anchors.verticalCenter: parent.verticalCenter
text: artist + " - " + title
color: Theme.deckTextColor
color: (listView.currentIndex == index && listView.activeFocus) ? Theme.blue : Theme.deckTextColor

Behavior on color {
ColorAnimation {
duration: listView.highlightMoveDuration
}

}

}

Image {
Expand All @@ -44,13 +112,24 @@ Item {

anchors.fill: parent
drag.target: dragItem
onPressed: parent.grabToImage((result) => {
dragItem.Drag.imageSource = result.url;
})
onPressed: {
listView.forceActiveFocus();
listView.currentIndex = index;
parent.grabToImage((result) => {
dragItem.Drag.imageSource = result.url;
});
}
onDoubleClicked: listView.loadSelectedTrackIntoNextAvailableDeck(false)
}

}

highlight: Rectangle {
border.color: listView.activeFocus ? Theme.blue : Theme.deckTextColor
border.width: 1
color: "transparent"
}

}

}
Expand Down
156 changes: 156 additions & 0 deletions res/qml/LibraryControl.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import Mixxx 0.1 as Mixxx
import QtQuick 2.12

Item {
id: root

property alias focusWidget: focusedWidgetControl.value

signal moveVertical(int offset)
signal loadSelectedTrack(string group, bool play)
signal loadSelectedTrackIntoNextAvailableDeck(bool play)

FocusedWidgetControl {
id: focusedWidgetControl

Component.onCompleted: this.value = FocusedWidgetControl.WidgetKind.LibraryView
}

Mixxx.ControlProxy {
group: "[Library]"
key: "GoToItem"
onValueChanged: {
if (value != 0 && root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView)
root.loadSelectedTrackIntoNextAvailableDeck(false);

}
}

Mixxx.ControlProxy {
group: "[Playlist]"
key: "LoadSelectedIntoFirstStopped"
onValueChanged: {
if (value != 0 && root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView)
root.loadSelectedTrackIntoNextAvailableDeck(false);

}
}

Mixxx.ControlProxy {
group: "[Playlist]"
key: "SelectTrackKnob"
onValueChanged: {
if (value != 0) {
root.focusWidget = FocusedWidgetControl.WidgetKind.LibraryView;
root.moveVertical(value);
}
}
}

Mixxx.ControlProxy {
group: "[Playlist]"
key: "SelectPrevTrack"
onValueChanged: {
if (value != 0) {
root.focusWidget = FocusedWidgetControl.WidgetKind.LibraryView;
root.moveVertical(-1);
}
}
}

Mixxx.ControlProxy {
group: "[Playlist]"
key: "SelectNextTrack"
onValueChanged: {
if (value != 0) {
root.focusWidget = FocusedWidgetControl.WidgetKind.LibraryView;
root.moveVertical(1);
}
}
}

Mixxx.ControlProxy {
group: "[Library]"
key: "MoveVertical"
onValueChanged: {
if (value != 0 && root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView)
root.moveVertical(value);

}
}

Mixxx.ControlProxy {
group: "[Library]"
key: "MoveUp"
onValueChanged: {
if (value != 0 && root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView)
root.moveVertical(-1);

}
}

Mixxx.ControlProxy {
group: "[Library]"
key: "MoveDown"
onValueChanged: {
if (value != 0 && root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView)
root.moveVertical(1);

}
}

Mixxx.ControlProxy {
id: numDecksControl

group: "[Master]"
key: "num_decks"
}

Instantiator {
model: numDecksControl.value

delegate: LibraryControlLoadSelectedTrackHandler {
group: "[Channel" + (index + 1) + "]"
enabled: root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView
onLoadTrackRequested: root.loadSelectedTrack(group, play)
}

}

Mixxx.ControlProxy {
id: numPreviewDecksControl

group: "[Master]"
key: "num_preview_decks"
}

Instantiator {
model: numPreviewDecksControl.value

delegate: LibraryControlLoadSelectedTrackHandler {
group: "[PreviewDeck" + (index + 1) + "]"
enabled: root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView
onLoadTrackRequested: root.loadSelectedTrack(group, play)
}

}

Mixxx.ControlProxy {
id: numSamplersControl

group: "[Master]"
key: "num_samplers"
}

Instantiator {
model: numSamplersControl.value

delegate: LibraryControlLoadSelectedTrackHandler {
group: "[Sampler" + (index + 1) + "]"
enabled: root.focusWidget == FocusedWidgetControl.WidgetKind.LibraryView
onLoadTrackRequested: root.loadSelectedTrack(group, play)
}

}

}
38 changes: 38 additions & 0 deletions res/qml/LibraryControlLoadSelectedTrackHandler.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Mixxx 0.1 as Mixxx
import QtQuick 2.12

/// Usually, this component shouldn't be an (visual) `Item` and use something
/// like `QtObject` instead. However, for some reason using `QtObject` here
/// makes Mixxx crash on load (using Qt 5.15.2+kde+r43-1). We can check if this
/// is fixed upstream once we switch to Qt 6.
Item {
id: root

property string group // required
property bool enabled: true

signal loadTrackRequested(bool play)

Mixxx.ControlProxy {
group: root.group
key: "LoadSelectedTrack"
onValueChanged: {
if (value == 0 || !root.enabled)
return ;

root.loadTrackRequested(false);
}
}

Mixxx.ControlProxy {
group: root.group
key: "LoadSelectedTrackAndPlay"
onValueChanged: {
if (value == 0 || !root.enabled)
return ;

root.loadTrackRequested(true);
}
}

}
14 changes: 14 additions & 0 deletions res/qml/Mixxx/MathUtils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,17 @@
export const clamp = function(value, min, max) {
return Math.max(Math.min(value, max), min);
};

/**
* @param {number} x Value
* @param {number} m Modulus
* @returns {number} Result of y where y = x modulo m and y > 0
*/
export const positiveModulo = function(x, m) {
console.assert(m > 0);
let result = x % m;
while (result < 0) {
result += m;
}
return result;
};
4 changes: 2 additions & 2 deletions src/library/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,11 @@ void Library::slotLoadTrack(TrackPointer pTrack) {
emit loadTrack(pTrack);
}

void Library::slotLoadLocationToPlayer(const QString& location, const QString& group) {
void Library::slotLoadLocationToPlayer(const QString& location, const QString& group, bool play) {
auto trackRef = TrackRef::fromFilePath(location);
TrackPointer pTrack = m_pTrackCollectionManager->getOrAddTrack(trackRef);
if (pTrack) {
emit loadTrackToPlayer(pTrack, group);
emit loadTrackToPlayer(pTrack, group, play);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/library/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class Library: public QObject {
void slotSwitchToView(const QString& view);
void slotLoadTrack(TrackPointer pTrack);
void slotLoadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play);
void slotLoadLocationToPlayer(const QString& location, const QString& group);
void slotLoadLocationToPlayer(const QString& location, const QString& group, bool play);
void slotRefreshLibraryModels();
void slotCreatePlaylist();
void slotCreateCrate();
Expand Down
Loading

0 comments on commit f1c7217

Please sign in to comment.