Files
stemify/desktop/stemify/player/qml/StemPlayer/StemChart.qml
T

137 lines
5.6 KiB
QML

import QtQuick
// The stem faders as an Excel column chart. Drag a column to set its level; double-click
// for 0 dB. Below each category: M(ute) and S(olo).
Rectangle {
id: ch
color: "#FFFFFF"
border.color: "#D9D9D9"
readonly property var stems: player.stems
readonly property int n: stems.length
readonly property real unity: 0.8
T {
id: title
anchors.horizontalCenter: parent.horizontalCenter
y: 6
text: "Stem Mix"
font.family: cellFont
font.pixelSize: 17
color: X.chartText
}
Item {
id: plot
x: 34
y: title.y + title.height + 18
width: parent.width - x - 8
height: parent.height - y - 52
// value axis: fader position, 0 dB marked
Repeater {
model: [0, 0.25, 0.5, 0.8, 1.0]
delegate: Item {
required property var modelData
y: plot.height * (1 - modelData)
width: plot.width
Rectangle { width: parent.width; height: 1; color: modelData === 0.8 ? "#A6A6A6" : X.chartLine }
T {
x: -32
width: 28
y: -7
height: 14
horizontalAlignment: Text.AlignRight
font.family: cellFont
font.pixelSize: 11
color: X.chartText
text: modelData === 0 ? "-∞" : modelData === 0.8 ? "0 dB" : modelData === 1 ? "+4" : (40 * Math.log(modelData / 0.8) / Math.LN10).toFixed(0)
}
}
}
Repeater {
model: ch.stems
delegate: Item {
id: cat
required property int index
required property var modelData
readonly property real cw: plot.width / Math.max(1, ch.n)
x: index * cw
width: cw
height: plot.height
Rectangle {
id: bar
anchors.horizontalCenter: parent.horizontalCenter
width: cat.cw * 0.62
height: Math.max(1, plot.height * cat.modelData.level)
y: plot.height - height
color: cat.modelData.color
opacity: cat.modelData.audible ? 1 : 0.22
border.color: dm.containsMouse || dm.pressed ? "#404040" : "transparent"
Behavior on height { enabled: !dm.pressed; NumberAnimation { duration: X.easeMs; easing.type: Easing.OutCubic } }
}
T { // data label
anchors.horizontalCenter: parent.horizontalCenter
y: bar.y - 16
font.family: cellFont
font.pixelSize: 11
color: X.chartText
text: cat.modelData.muted ? "Muted" : !cat.modelData.audible ? "—" : cat.modelData.level <= 0.001 ? "-∞" : (cat.modelData.db >= 0 ? "+" : "") + cat.modelData.db.toFixed(1)
}
MouseArea {
id: dm
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.SizeVerCursor
function set(m) { player.setLevel(cat.index, Math.max(0, Math.min(1, 1 - m.y / plot.height))) }
onPressed: (m) => set(m)
onPositionChanged: (m) => { if (pressed) set(m) }
onDoubleClicked: player.setLevel(cat.index, ch.unity)
onWheel: (w) => player.setLevel(cat.index, Math.max(0, Math.min(1, cat.modelData.level + (w.angleDelta.y > 0 ? 0.02 : -0.02))))
}
Tip { target: dm; text: cat.modelData.label + ": drag to set, double-click for 0 dB" }
// category axis label and the M / S toggles
Column {
y: plot.height + 4
anchors.horizontalCenter: parent.horizontalCenter
spacing: 3
T {
anchors.horizontalCenter: parent.horizontalCenter
font.family: cellFont
font.pixelSize: 12
color: X.chartText
text: cat.modelData.label
width: Math.min(implicitWidth, cat.cw)
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 2
Toggle { label: "M"; on: cat.modelData.muted; onFill: X.bad; onText: X.badText; tip: "Mute " + cat.modelData.label; onClicked: player.toggleMute(cat.index) }
Toggle { label: "S"; on: cat.modelData.solo; onFill: X.neutral; onText: X.neutralText; tip: "Solo " + cat.modelData.label; onClicked: player.toggleSolo(cat.index) }
}
}
}
}
Rectangle { y: plot.height; width: plot.width; height: 1; color: "#BFBFBF" }
}
component Toggle: Rectangle {
id: tg
property string label
property bool on: false
property color onFill
property color onText
property string tip
signal clicked()
width: 18
height: 18
color: on ? onFill : tgm.containsMouse ? "#F2F2F2" : "#FFFFFF"
border.color: on ? onText : "#BFBFBF"
T { anchors.centerIn: parent; text: tg.label; font.pixelSize: 11; font.bold: tg.on; color: tg.on ? tg.onText : X.inkSoft }
MouseArea { id: tgm; anchors.fill: parent; hoverEnabled: true; onClicked: tg.clicked() }
Tip { target: tgm; text: tg.tip }
}
}