Warning, /multimedia/kasts/src/qml/ChapterSlider.qml is written in an unsupported language. File is not indexed.

0001 /**
0002  * SPDX-FileCopyrightText: 2023 Tobias Fella <fella@posteo.de>
0003  * SPDX-FileCopyrightText: 2023 Bart De Vries <bart@mogwai.be>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  */
0007 
0008 import QtQuick
0009 import QtQuick.Controls
0010 import QtQuick.Layouts
0011 
0012 import org.kde.kirigami as Kirigami
0013 
0014 import org.kde.kasts
0015 
0016 Control {
0017     id: root
0018 
0019     property alias model: chapters.model
0020 
0021     property int value: AudioManager.position
0022     property int duration: AudioManager.duration
0023 
0024     Kirigami.Theme.colorSet: Kirigami.Theme.Button
0025     Kirigami.Theme.inherit: false
0026 
0027     implicitHeight: handle.height
0028     implicitWidth: 200
0029 
0030     // metrics used by the default font
0031     property var fontMetrics: FontMetrics {
0032         property real fullWidthCharWidth: fontMetrics.tightBoundingRect('_').width
0033     }
0034 
0035     // align with the Slider implementations in the major styles
0036     readonly property bool desktopStyle: styleName === "org.kde.desktop"
0037     readonly property color inactiveGrooveColor: desktopStyle ? Kirigami.ColorUtils.scaleColor(inactiveGrooveBorderColor, {alpha: -50}) : Kirigami.Theme.backgroundColor
0038     readonly property color activeGrooveColor: desktopStyle ? Kirigami.ColorUtils.scaleColor(activeGrooveBorderColor, {alpha: -50}) : Kirigami.Theme.alternateBackgroundColor
0039     readonly property color inactiveGrooveBorderColor: desktopStyle ? Kirigami.ColorUtils.scaleColor(Kirigami.Theme.textColor, {alpha: -80}) : Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.3)
0040     readonly property color activeGrooveBorderColor: desktopStyle ? Kirigami.Theme.highlightColor : Kirigami.Theme.focusColor
0041     readonly property color handleColor: Kirigami.Theme.backgroundColor
0042     readonly property color handleBorderColor: dragArea.pressed || dragArea.containsMouse ? Kirigami.Theme.focusColor : Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.4)
0043 
0044     readonly property int grooveSize: {
0045         if (desktopStyle) {
0046             return 6;
0047         } else {
0048             let h = Math.floor(fontMetrics.height / 3);
0049             h += h % 2;
0050             return h;
0051         }
0052     }
0053     readonly property int handleSize: desktopStyle ? 20 : fontMetrics.height
0054 
0055     function setPlaybackPosition(x) {
0056         AudioManager.position = (Math.max(handle.width / 2, Math.min(x, root.width - handle.width / 2)) - handle.width / 2) / (root.width - handle.width) * duration
0057     }
0058 
0059     MouseArea {
0060         anchors.fill: parent
0061         onReleased: {
0062             setPlaybackPosition(mouseX)
0063         }
0064         // TODO: handle scrollwheel
0065     }
0066 
0067     RowLayout {
0068         id: layout
0069         anchors.fill: parent
0070         anchors.leftMargin: handle.width / 2
0071         anchors.rightMargin: handle.width / 2
0072         spacing: 0
0073         Repeater {
0074             id: chapters
0075             delegate: Rectangle {
0076                 // If we're not dragging, use the more precise method using the AudioManager. If we're dragging, this doesn't work because the AudioManager isn't updated while dragging
0077                 readonly property bool isCurrent: dragArea.drag.active ? (x - 1.01 <= handle.centerX && handle.centerX < x + width) : (model.start * 1000 <= AudioManager.position && (model.start + model.duration) * 1000 > AudioManager.position)
0078                 readonly property bool isPrevious: dragArea.drag.active ? (x + width < handle.centerX) : ((model.start + model.duration) * 1000 < AudioManager.position)
0079                 Layout.preferredWidth: model.duration * 1000 / root.duration * (layout.width - chapters.count + 1)
0080                 Layout.preferredHeight: grooveSize
0081                 Layout.alignment: Qt.AlignVCenter
0082                 radius: height / 2
0083 
0084                 z: 1
0085                 color: inactiveGrooveColor
0086                 border {
0087                     width: 1
0088                     color: inactiveGrooveBorderColor
0089                 }
0090                 MouseArea {
0091                     anchors.fill: parent
0092                     hoverEnabled: true
0093                     z: 0
0094                     ToolTip {
0095                         text: model.title
0096                         visible: parent.containsMouse
0097                     }
0098                     onReleased: {
0099                         setPlaybackPosition(mouseX + parent.x + handle.width / 2)
0100                     }
0101                 }
0102                 Rectangle {
0103                     visible: isCurrent || isPrevious
0104                     anchors.left: parent.left
0105                     anchors.top: parent.top
0106                     anchors.bottom: parent.bottom
0107                     width: isCurrent ? handle.centerX - parent.x : parent.width
0108                     radius: parent.height / 2
0109                     color: activeGrooveColor
0110                     border {
0111                         width: 1
0112                         color: activeGrooveBorderColor
0113                     }
0114                 }
0115             }
0116         }
0117     }
0118 
0119     Rectangle {
0120         color: inactiveGrooveColor
0121         visible: chapters.count === 0
0122         border {
0123             width: 1
0124             color: inactiveGrooveBorderColor
0125         }
0126         width: parent.width - handle.width
0127         height: grooveSize
0128         radius: height / 2
0129         anchors.centerIn: parent
0130         Rectangle {
0131             anchors.left: parent.left
0132             anchors.top: parent.top
0133             anchors.bottom: parent.bottom
0134             width: handle.centerX - parent.x
0135             radius: parent.height / 2
0136             color: activeGrooveColor
0137             border {
0138                 width: 1
0139                 color: activeGrooveBorderColor
0140             }
0141         }
0142     }
0143 
0144     Rectangle {
0145         id: handle
0146 
0147         property int centerX: x + width / 2
0148 
0149         Kirigami.Theme.inherit: false
0150         Kirigami.Theme.colorSet: Kirigami.Theme.Button
0151 
0152         height: root.handleSize
0153         width: height
0154         radius: width / 2
0155         anchors.verticalCenter: root.verticalCenter
0156         color: handleColor
0157         border.width: 1
0158         border.color: handleBorderColor
0159         x: dragArea.drag.active ? 0 : root.value / root.duration * (root.width - handle.width)
0160         z: 2
0161 
0162         MouseArea {
0163             id: dragArea
0164             anchors.fill: parent
0165             hoverEnabled: true
0166             drag {
0167                 target: handle
0168                 axis: Drag.XAxis
0169                 minimumX: 0
0170                 maximumX: root.width - handle.width
0171                 threshold: 0
0172             }
0173             onReleased: setPlaybackPosition(handle.x + handle.width / 2)
0174         }
0175     }
0176 }