mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-14 23:34:01 -04:00
151 lines
5.6 KiB
QML
151 lines
5.6 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import qs.Common
|
|
import qs.Modules.OSD
|
|
import qs.DCommon.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
required property var systemModel
|
|
property bool isVertical: false
|
|
property real iconSize: 36
|
|
|
|
readonly property int maximum: Math.max(root.systemModel.minimum + 1, Math.round(root.systemModel.maximum))
|
|
readonly property real fillRatio: Math.max(0, Math.min(1, (root.systemModel.value - root.systemModel.minimum) / Math.max(1, root.maximum - root.systemModel.minimum)))
|
|
// DSlider's own metrics, transposed, so the two orientations read as the same control.
|
|
readonly property real trackThickness: 12
|
|
readonly property real handleThickness: 4
|
|
readonly property real handleBreadth: 20
|
|
readonly property real fillHandleGap: 3
|
|
|
|
function trackFraction(localY) {
|
|
if (track.travel <= 0)
|
|
return 0;
|
|
return 1 - (localY - root.handleThickness / 2) / track.travel;
|
|
}
|
|
|
|
function applyFraction(fraction) {
|
|
const clamped = Math.max(0, Math.min(1, fraction));
|
|
const level = root.systemModel.minimum + clamped * (root.maximum - root.systemModel.minimum);
|
|
root.systemModel.setRatio(level / Math.max(1, root.maximum));
|
|
}
|
|
|
|
OsdLevelRow {
|
|
anchors.fill: parent
|
|
visible: !root.isVertical
|
|
iconName: root.systemModel.iconName
|
|
tonalIcon: false
|
|
iconInteractive: root.systemModel.mutable
|
|
iconLabel: root.systemModel.muted ? I18n.tr("Unmute") : I18n.tr("Mute")
|
|
value: Math.round(root.systemModel.value)
|
|
minimum: root.systemModel.minimum
|
|
maximum: root.maximum
|
|
unit: root.systemModel.unit
|
|
displayText: root.systemModel.displayValue
|
|
sliderEnabled: root.systemModel.available
|
|
onIconClicked: root.systemModel.toggleMute()
|
|
onSliderValueChanged: newValue => root.systemModel.setRatio(newValue / Math.max(1, root.maximum))
|
|
}
|
|
|
|
// DSlider is horizontal only, so a side strip gets its own stacked track.
|
|
Item {
|
|
id: verticalFace
|
|
|
|
anchors.fill: parent
|
|
anchors.topMargin: Theme.spacingS
|
|
anchors.bottomMargin: Theme.spacingS
|
|
visible: root.isVertical
|
|
|
|
DIcon {
|
|
id: levelIcon
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
name: root.systemModel.iconName
|
|
size: Math.min(Theme.iconSize, root.iconSize)
|
|
color: root.systemModel.mutable ? Theme.surfaceText : Theme.primary
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: root.systemModel.mutable
|
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
onClicked: root.systemModel.toggleMute()
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
id: levelLabel
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
text: root.systemModel.displayValue.length > 0 ? root.systemModel.displayValue : (Math.round(root.systemModel.value) + root.systemModel.unit)
|
|
color: Theme.surfaceText
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Theme.fontWeightMedium
|
|
}
|
|
|
|
Item {
|
|
id: track
|
|
|
|
readonly property real travel: Math.max(0, height - root.handleThickness)
|
|
readonly property real handleOffset: track.travel * root.fillRatio
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: levelIcon.bottom
|
|
anchors.topMargin: Theme.spacingS
|
|
anchors.bottom: levelLabel.top
|
|
anchors.bottomMargin: Theme.spacingS
|
|
width: root.handleBreadth
|
|
|
|
Rectangle {
|
|
id: groove
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
anchors.bottom: parent.bottom
|
|
width: root.trackThickness
|
|
radius: Theme.cornerRadius
|
|
color: Theme.withAlpha(Theme.outline, Theme.foregroundAlpha)
|
|
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
height: Math.max(0, Math.min(parent.height, track.handleOffset - root.fillHandleGap))
|
|
radius: Theme.cornerRadius
|
|
topLeftRadius: 0
|
|
topRightRadius: 0
|
|
color: root.systemModel.available ? Theme.primary : Theme.withAlpha(Theme.surfaceText, 0.12)
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
y: track.travel - track.handleOffset
|
|
width: root.handleBreadth
|
|
height: root.handleThickness
|
|
radius: Theme.cornerRadius
|
|
color: root.systemModel.available ? Theme.primary : Theme.withAlpha(Theme.surfaceText, 0.12)
|
|
}
|
|
|
|
MouseArea {
|
|
id: trackArea
|
|
|
|
readonly property real grabPad: Theme.spacingS
|
|
|
|
anchors.fill: parent
|
|
anchors.margins: -grabPad
|
|
enabled: root.systemModel.available
|
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
onPressed: mouse => root.applyFraction(root.trackFraction(mouse.y - grabPad))
|
|
onPositionChanged: mouse => {
|
|
if (pressed)
|
|
root.applyFraction(root.trackFraction(mouse.y - grabPad));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|