feature: a much nicer qml rangedslider

In order to make start and end time setting far more efficient, I
decided to create my own RangeSlider called RangedSlider. This has a
moved signal for each handle and a released signal for each
handle. This allows us to change the video playback but not set the
value until released. Meaning only one access to the database.
This commit is contained in:
Chris Cochrun 2023-04-19 05:35:52 -05:00
parent 8b231de32b
commit 81ea712c6b
2 changed files with 131 additions and 124 deletions

View file

@ -14,13 +14,18 @@ Rectangle {
property real firstValue
property real secondValue
property real firstInitialValue
property real secondInitialValue
property real firstVisualPosition
property real secondVisualPosition
signal firstReleased()
signal secondReleased()
signal firstMoved()
signal secondMoved()
Kirigami.Theme.colorSet: Kirigami.Theme.Button
Kirigami.Theme.inherit: false
color: Kirigami.Theme.backgroundColor
border.width: 0
@ -28,31 +33,32 @@ Rectangle {
height: 6
Rectangle {
id: range
color: Kirigami.Theme.hoverColor
height: root.height
radius: width / 2
border.width: 0
anchors.right: second.right
anchors.left: first.left
}
Rectangle {
id: first
x: firstVisualPosition
x: firstInitialValue / (to - from) * (root.width - width)
y: -6
implicitWidth: 18
implicitHeight: 18
color: firstMouse.containsMouse ? Kirigami.Theme.hoverColor : Kirigami.Theme.alternateBackgroundColor
border.width: firstMouse.containsMouse ? 2 : 1
border.color: firstMouse.containsMouse ? Kirigami.Theme.hoverColor : Kirigami.Theme.backgroundColor
color: firstMouse.containsMouse || firstMouse.drag.active ? Kirigami.Theme.hoverColor : Kirigami.Theme.alternateBackgroundColor
border.width: firstMouse.containsMouse || firstMouse.drag.active ? 2 : 1
border.color: firstMouse.containsMouse || firstMouse.drag.active ? Kirigami.Theme.hoverColor : Kirigami.Theme.backgroundColor
radius: width / 2
Drag.active: firstMouse.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
/* states: State { */
/* name: "dragged" */
/* when: first.Drag.active */
/* PropertyChanges { */
/* target: first */
/* x: x */
/* width: width */
/* height: height */
/* } */
/* } */
MouseArea {
id: firstMouse
anchors.fill: parent
@ -60,41 +66,38 @@ Rectangle {
drag {
target: first
axis: Drag.XAxis
maximumX: root.right
minimumX: root.left
maximumX: Math.min((root.width - first.width / 2), second.x)
minimumX: 0 + first.width / 2
}
onReleased: {
firstValue = mouseX;
firstValue = (to - from) / (root.width - first.width) * (first.x - first.width / 2) + from;
firstVisualPosition = firstValue;
firstReleased();
}
onPositionChanged: {
if (drag.active) {
firstVisualPosition = (to - from) / (root.width - first.width) * (first.x - first.width / 2) + from;
firstMoved()
}
}
}
}
Rectangle {
id: second
x: secondVisualPosition
x: secondInitialValue / (to - from) * (root.width - width)
y: -6
implicitWidth: 18
implicitHeight: 18
color: secondMouse.containsMouse ? Kirigami.Theme.hoverColor : Kirigami.Theme.alternateBackgroundColor
border.width: secondMouse.containsMouse ? 2 : 1
border.color: secondMouse.containsMouse ? Kirigami.Theme.hoverColor : Kirigami.Theme.backgroundColor
color: secondMouse.containsMouse || secondMouse.drag.active ? Kirigami.Theme.hoverColor : Kirigami.Theme.alternateBackgroundColor
border.width: secondMouse.containsMouse || secondMouse.drag.active ? 2 : 1
border.color: secondMouse.containsMouse || secondMouse.drag.active ? Kirigami.Theme.hoverColor : Kirigami.Theme.backgroundColor
radius: width / 2
Drag.active: secondMouse.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
/* states: State { */
/* name: "dragged" */
/* when: second.Drag.active */
/* PropertyChanges { */
/* target: second */
/* x: x */
/* width: width */
/* height: height */
/* } */
/* } */
MouseArea {
id: secondMouse
anchors.fill: parent
@ -102,19 +105,25 @@ Rectangle {
drag {
target: second
axis: Drag.XAxis
maximumX: root.width
minimumX: 0
maximumX: root.width - second.width / 2
minimumX: Math.max((0 + second.width / 2), first.x)
}
onReleased: {
secondValue = second.x;
secondValue = (to - from) / (root.width - second.width) * (second.x - second.width / 2) + from;
secondVisualPosition = secondValue;
secondReleased();
}
onPositionChanged: {
if (drag.active) {
secondVisualPosition = (to - from) / (root.width - second.width) * (second.x - second.width / 2) + from;
secondMoved()
}
}
}
}
Rectangle {
id: range
color: Kirigami.Theme.hoverColor
radius: width / 2
}
/* function setValues(first, second) { */
/* first.x = first */
/* second.x = second */
/* } */
}

View file

@ -80,10 +80,12 @@ Item {
Item {
Layout.columnSpan: 2
Layout.preferredWidth: root.width - 50
Layout.preferredHeight: Layout.preferredWidth / 16 * 9
Layout.fillWidth: true
Layout.preferredHeight: width / 16 * 9
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 10
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
MpvObject {
id: videoPreview
@ -100,44 +102,36 @@ Item {
}
}
Rectangle {
id: videoBg
color: Kirigami.Theme.alternateBackgroundColor
RowLayout {
anchors.top: videoPreview.bottom
width: parent.width
width: videoPreview.width
height: videoTitleField.height
RowLayout {
anchors.fill: parent
spacing: 2
Kirigami.Icon {
source: videoPreview.isPlaying ? "media-pause" : "media-play"
Layout.preferredWidth: 25
Layout.preferredHeight: 25
MouseArea {
anchors.fill: parent
onPressed: videoPreview.playPause()
cursorShape: Qt.PointingHandCursor
}
}
Controls.Slider {
id: videoSlider
Layout.fillWidth: true
Layout.preferredHeight: 25
from: 0
to: videoPreview.duration
/* value: videoPreview.postion */
live: true
onMoved: videoPreview.seek(value);
}
Controls.Label {
id: videoTime
text: new Date(videoPreview.position * 1000).toISOString().slice(11, 19);
spacing: 2
Kirigami.Icon {
source: videoPreview.isPlaying ? "media-pause" : "media-play"
Layout.preferredWidth: 25
Layout.preferredHeight: 25
MouseArea {
anchors.fill: parent
onPressed: videoPreview.playPause()
cursorShape: Qt.PointingHandCursor
}
}
Controls.Slider {
id: videoSlider
Layout.fillWidth: true
Layout.preferredHeight: 25
from: 0
to: videoPreview.duration
/* value: videoPreview.postion */
live: true
onMoved: videoPreview.seek(value);
}
Controls.Label {
id: videoTime
text: new Date(videoPreview.position * 1000).toISOString().slice(11, 19);
}
}
}
@ -145,67 +139,79 @@ Item {
id: videoRangeBox
Layout.columnSpan: 2
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
Layout.leftMargin: 25
Layout.rightMargin: 25
Layout.topMargin: 40
visible: editingRange
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Layout.topMargin: Kirigami.Units.largeSpacing * 3
Layout.bottomMargin: Kirigami.Units.largeSpacing * 3
/* visible: editingRange */
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
color: Kirigami.Theme.backgroundColor
border.width: 1
border.color: Kirigami.Theme.disabledTextColor
radius: 6
ColumnLayout {
anchors.fill: parent
Controls.RangeSlider {
id: videoLengthSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.leftMargin: 25
Layout.rightMargin: 25
to: videoPreview.duration
from: 0
stepSize: 0.1
snapMode: Controls.RangeSlider.SnapAlways
first.value: video.startTime
second.value: video.endTime
first.onMoved: updateStartTime(first.value)
second.onMoved: updateEndTime(second.value)
anchors {
fill: parent
topMargin: 5
bottomMargin: 5
leftMargin: 5
rightMargin: 5
}
Controls.Label {
text: "Adjust start and end times:"
Rectangle {
anchors.top: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: Kirigami.Units.smallSpacing / 3
color: Kirigami.Theme.disabledTextColor
}
}
Presenter.RangedSlider {
id: videoLengthSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.leftMargin: 25
Layout.rightMargin: 25
Layout.topMargin: Kirigami.Units.smallSpacing * 3
/* Layout.leftMargin: 25 */
/* Layout.rightMargin: 25 */
onFirstReleased: showPassiveNotification("first")
onSecondReleased: showPassiveNotification("Second")
from: 0
to: videoPreview.duration
firstInitialValue: video.startTime
secondInitialValue: video.endTime
onFirstMoved: videoPreview.seek(firstVisualPosition)
onSecondMoved: videoPreview.seek(secondVisualPosition)
onFirstReleased: updateStartTime(firstValue)
onSecondReleased: updateEndTime(secondValue)
}
RowLayout {
Layout.preferredWidth: parent.width
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: 25
Layout.rightMargin: 25
Controls.Label {
Controls.TextField {
Layout.alignment: Qt.AlignLeft
text: "Start Time: " + new Date(videoLengthSlider.first.value * 1000).toISOString().slice(11, 19);
text: "Start Time: " + new Date(videoLengthSlider.firstVisualPosition * 1000).toISOString().slice(11, 19);
horizontalAlignment: TextInput.AlignHCenter
}
Controls.Label {
Controls.TextField {
Layout.alignment: Qt.AlignRight
text: "End Time: " + new Date(videoLengthSlider.second.value * 1000).toISOString().slice(11, 19);
text: "End Time: " + new Date(videoLengthSlider.secondVisualPosition * 1000).toISOString().slice(11, 19);
horizontalAlignment: TextInput.AlignHCenter
}
}
Controls.ToolButton {
text: "FIX"
onClicked: videoLengthSlider.setValues(video.startTime, video.endTime)
}
}
}
@ -236,8 +242,6 @@ Item {
interval: 100
onTriggered: {
videoPreview.loadFile(video.filePath.toString());
videoLengthSlider.setValues(video.startTime, video.endTime);
/* showPassiveNotification(video[0]); */
}
}
@ -247,7 +251,6 @@ Item {
console.log(video.startTime);
console.log(video.endTime);
mpvLoadingTimer.restart();
videoLengthSlider.setValues(vid.startTime, vid.endTime);
footerLeftString = "File path: " + video.filePath
}
@ -258,18 +261,13 @@ Item {
}
function updateEndTime(value) {
videoPreview.seek(value);
videoProxyModel.updateEndTime(video.id, value);
videoProxyModel.updateEndTime(video.id, Math.min(value, videoPreview.duration));
video.endTime = value;
/* showPassiveNotification(video.endTime); */
}
function updateStartTime(value) {
/* changeStartTime(value, false); */
videoPreview.seek(value);
videoProxyModel.updateStartTime(video.id, value);
videoProxyModel.updateStartTime(video.id, Math.max(value, 0));
video.startTime = value;
/* showPassiveNotification(value); */
}
function updateTitle(text) {