diff --git a/res/qml/legacy/Button.qml b/res/qml/legacy/Button.qml
new file mode 100644
index 000000000000..746c5771b264
--- /dev/null
+++ b/res/qml/legacy/Button.qml
@@ -0,0 +1,64 @@
+import QtQuick
+import QtQuick.Controls
+// import skin.mixxx.org // for ColorScheme singleton
+
+Button {
+ id: control
+ property color color: "transparent"
+ implicitHeight: 24
+ implicitWidth: Math.max(implicitHeight, Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding))
+ font.bold: true
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: checked ? "#000000" : "#908070"
+ // color: checked ? "#000000" : ColorScheme.buttonText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ color: control.color
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ border.color: "#000000"
+ border.width: 1
+ color: "transparent"
+ }
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ border.color: "#000000"
+ border.width: 1
+ radius: 2
+ color: "transparent"
+ }
+ Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: "transparent"
+ border.color: control.pressed ? "#60000000" : "#04ffffff"
+ border.width: 1
+ radius: 2
+ }
+ Rectangle {
+ x: 2
+ y: 1
+ width: parent.width - 3
+ height: 1
+ color: control.pressed ? "#04ffffff" : "#0cffffff"
+ }
+ Image {
+ width: control.width
+ height: control.height
+ source: control.icon.source
+ fillMode: Image.PreserveAspectFit
+ }
+ }
+}
diff --git a/res/qml/legacy/CenterMixerComponent.qml b/res/qml/legacy/CenterMixerComponent.qml
new file mode 100644
index 000000000000..4b2dea9f6c1a
--- /dev/null
+++ b/res/qml/legacy/CenterMixerComponent.qml
@@ -0,0 +1,30 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+Item {
+ id: root
+ width: mixer.implicitWidth
+ height: mixer.implicitHeight
+
+ RowLayout {
+ spacing: 0
+ id: mixer
+ E.Mixer {
+ Layout.fillHeight: true
+ }
+ Item {
+ Layout.fillHeight: true
+ width: childrenRect.width
+ E.MainMix {
+ height: parent.height / 2
+ }
+ E.HeadphoneMix {
+ y: parent.height / 2
+ height: parent.height / 2
+ }
+ }
+ }
+}
diff --git a/res/qml/legacy/ColorScheme.qml b/res/qml/legacy/ColorScheme.qml
new file mode 100644
index 000000000000..e8a75dd1c324
--- /dev/null
+++ b/res/qml/legacy/ColorScheme.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+QtObject {
+ property color buttonText
+}
diff --git a/res/qml/legacy/ColorSchemeBright.qml b/res/qml/legacy/ColorSchemeBright.qml
new file mode 100644
index 000000000000..62e2ed29c534
--- /dev/null
+++ b/res/qml/legacy/ColorSchemeBright.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+ColorScheme {
+ buttonText: "#ffffff"
+}
diff --git a/res/qml/legacy/ColorSchemeDefault.qml b/res/qml/legacy/ColorSchemeDefault.qml
new file mode 100644
index 000000000000..dfaa68a2d68e
--- /dev/null
+++ b/res/qml/legacy/ColorSchemeDefault.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+ColorScheme {
+ buttonText: "#908070"
+}
diff --git a/res/qml/legacy/CueButton.qml b/res/qml/legacy/CueButton.qml
new file mode 100644
index 000000000000..54d31af39a74
--- /dev/null
+++ b/res/qml/legacy/CueButton.qml
@@ -0,0 +1,37 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Button {
+ id: control
+ property int cueId: 0
+ implicitWidth: 24
+ implicitHeight: 24
+ color: checked ? "#c06020" : "#202020"
+ text: cueId
+ font.pixelSize: 14
+ MouseArea {
+ width: parent.width
+ height: parent.height
+ propagateComposedEvents: true
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onPressed: mouse => {
+ if ((mouse.button == Qt.RightButton) && (mouse.modifiers & Qt.ShiftModifier)) {
+ if (control.checked) {
+ control.toggle();
+ }
+ } else if (!control.checked) {
+ control.toggle();
+ }
+ // propagate to Button for pressed state
+ mouse.accepted = false;
+ }
+ }
+ onPressed: {
+ }
+ onReleased: {
+ }
+ onClicked: {
+ }
+}
diff --git a/res/qml/legacy/Deck.qml b/res/qml/legacy/Deck.qml
new file mode 100644
index 000000000000..51c888266c06
--- /dev/null
+++ b/res/qml/legacy/Deck.qml
@@ -0,0 +1,147 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+E.Frame {
+ color: "#202020"
+ Layout.minimumWidth: 200
+ padding: 4
+ ColumnLayout {
+ height: parent.height
+ width: parent.width
+ spacing: 0
+ Item {
+ Layout.fillHeight: true
+ }
+ // Playback/Cue
+ RowLayout {
+ // Playback/Cue section
+ GridLayout {
+ columnSpacing: 2
+ rowSpacing: 2
+ columns: 2
+ // Cue
+ Button {
+ text: "CUE"
+ color: "#141414"
+ }
+ // Reverse
+ Button {
+ color: "#141414"
+ implicitWidth: 24
+ }
+ // Play/Pause
+ Button {
+ color: "#141414"
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ }
+ }
+ // Spacer
+ Item {
+ Layout.fillWidth: true
+ }
+ // Hotcues section
+ GridLayout {
+ columnSpacing: 2
+ rowSpacing: 2
+ columns: 4
+ CueButton {
+ text: "1"
+ }
+ CueButton {
+ text: "2"
+ }
+ CueButton {
+ text: "3"
+ }
+ CueButton {
+ text: "4"
+ }
+ CueButton {
+ text: "5"
+ }
+ CueButton {
+ text: "6"
+ }
+ CueButton {
+ text: "7"
+ }
+ CueButton {
+ text: "8"
+ }
+ }
+ // spacer
+ Item {
+ Layout.fillWidth: true
+ }
+ // Intro/Outro section
+ GridLayout {
+ columnSpacing: 2
+ rowSpacing: 2
+ columns: 2
+ IntroOutroButton {
+ }
+ IntroOutroButton {
+ }
+ IntroOutroButton {
+ }
+ IntroOutroButton {
+ }
+ }
+ // spacer
+ Item {
+ Layout.fillWidth: true
+ }
+ // Beatloop section
+ ColumnLayout {
+ spacing: 2
+ RowLayout {
+ spacing: 2
+ LoopButton {
+ }
+ SpinBox {
+ editable: true
+ from: 0
+ to: 512
+ }
+ }
+ RowLayout {
+ Layout.maximumWidth: childrenRect.width
+ spacing: 2
+ LoopToggleButton {
+ }
+ LoopButton {
+ }
+ LoopButton {
+ }
+ }
+ }
+ // spacer
+ Item {
+ Layout.fillWidth: true
+ }
+ // Loopjump section
+ ColumnLayout {
+ spacing: 2
+ RowLayout {
+ SpinBox {
+ editable: true
+ from: 0
+ to: 512
+ }
+ }
+ RowLayout {
+ spacing: 2
+ Layout.maximumWidth: childrenRect.width
+ LoopButton {
+ }
+ LoopButton {
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/res/qml/legacy/Dial.qml b/res/qml/legacy/Dial.qml
new file mode 100644
index 000000000000..d8453738d254
--- /dev/null
+++ b/res/qml/legacy/Dial.qml
@@ -0,0 +1,100 @@
+import QtQuick
+import QtQuick.Controls
+
+Dial {
+ id: control
+ inputMode: Dial.Vertical
+ wheelEnabled: true
+ implicitWidth: 36
+ implicitHeight: 36
+
+ property string color: "#808080"
+
+ background: Image {
+ source: "image://svgmodifier/dial/background.svg"
+ x: 0
+ y: 0
+ width: control.width
+ height: control.height
+ }
+
+ handle: Item {
+ readonly property bool trackFromCenter: from === -to
+ x: 0
+ y: 0
+ width: control.width
+ height: control.height
+ Item {
+ x: 0
+ y: 0
+ width: control.width / 2
+ height: control.height
+ clip: true
+ transform: [
+ Rotation {
+ angle: handle.trackFromCenter ? 0 : 40
+ origin.x: control.width / 2
+ origin.y: control.height / 2
+ }
+ ]
+ Image {
+ source: "image://svgmodifier/dial/track.svg?#ff0000/" + control.color
+ x: 0
+ y: 0
+ width: control.width
+ height: control.height
+ visible: !handle.trackFromCenter || control.angle <= 0
+ transform: [
+ Rotation {
+ angle: handle.trackFromCenter ? control.angle + 180 : control.angle < 40 ? control.angle - 40 : 0
+ origin.x: control.width / 2
+ origin.y: control.height / 2
+ }
+ ]
+ }
+ }
+ Item {
+ x: control.width / 2
+ y: 0
+ width: control.width / 2
+ height: control.height
+ clip: true
+ Image {
+ source: "image://svgmodifier/dial/track.svg?#ff0000/" + control.color
+ visible: control.angle >= 0
+ x: -control.width / 2
+ y: 0
+ width: control.width
+ height: control.height
+ transform: [
+ Rotation {
+ angle: control.angle
+ origin.x: control.width / 2
+ origin.y: control.height / 2
+ }
+ ]
+ }
+ }
+ Image {
+ source: "image://svgmodifier/dial/foreground.svg"
+ x: 0
+ y: 0
+ width: control.width
+ height: control.height
+ }
+ Image {
+ x: 0
+ y: 0
+ source: "image://svgmodifier/dial/handle.svg?#ff0000/" + control.color
+ width: control.width
+ height: control.height
+ transform: [
+ Rotation {
+ angle: control.angle
+ origin.x: control.width / 2
+ origin.y: control.height / 2
+ }
+ ]
+ }
+ }
+}
diff --git a/res/qml/legacy/EqDial.qml b/res/qml/legacy/EqDial.qml
new file mode 100644
index 000000000000..c9dad9e9c72a
--- /dev/null
+++ b/res/qml/legacy/EqDial.qml
@@ -0,0 +1,11 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Dial {
+ from: 0
+ to: 2
+ value: 1
+ color: "#808080"
+}
diff --git a/res/qml/legacy/EqFxSection.qml b/res/qml/legacy/EqFxSection.qml
new file mode 100644
index 000000000000..a8bd1f2840f2
--- /dev/null
+++ b/res/qml/legacy/EqFxSection.qml
@@ -0,0 +1,56 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+import Mixxx 1.0 as Mixxx
+
+GridLayout {
+ Layout.alignment: Qt.AlignTop
+ rowSpacing: 0
+ columnSpacing: 2
+ columns: 2
+ E.EqKillButton {
+ band: "H"
+ Layout.alignment: Qt.AlignVCenter
+ onCheckedChanged: filterHighKill.parameter = checked
+
+ Mixxx.ControlProxy {
+ id: filterHighKill
+
+ group: "[Channel1]"
+ key: "filterHighKill"
+ }
+ }
+ E.EqDial {
+ Mixxx.ControlProxy {
+ id: filterHigh
+
+ group: "[Channel1]"
+ key: "filterHigh"
+ }
+
+ value: filterHigh.parameter
+ onMoved: filterHigh.parameter = value
+
+ TapHandler {
+ onDoubleTapped: filterHigh.reset()
+ }
+ }
+ E.EqKillButton {
+ band: "M"
+ Layout.alignment: Qt.AlignVCenter
+ }
+ E.EqDial {
+ }
+ E.EqKillButton {
+ band: "L"
+ Layout.alignment: Qt.AlignVCenter
+ }
+ E.EqDial {
+ }
+ E.FxButton {
+ }
+ E.FxDial {
+ }
+}
diff --git a/res/qml/legacy/EqKillButton.qml b/res/qml/legacy/EqKillButton.qml
new file mode 100644
index 000000000000..5bc8903fe88a
--- /dev/null
+++ b/res/qml/legacy/EqKillButton.qml
@@ -0,0 +1,16 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Button {
+ id: control
+ property string band
+ implicitWidth: 18
+ implicitHeight: 18
+ color: control.checked ? "#b00000" : "#121212"
+ text: control.checked ? "" : band
+ font.family: "Open Sans"
+ font.weight: Font.DemiBold
+ onPressed: control.toggle()
+}
diff --git a/res/qml/legacy/Frame.qml b/res/qml/legacy/Frame.qml
new file mode 100644
index 000000000000..f667da4b85a1
--- /dev/null
+++ b/res/qml/legacy/Frame.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.Controls
+
+Frame {
+ id: control
+ property color color: "transparent"
+ background: Rectangle {
+ color: control.color
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: "#04ffffff"
+ }
+ Rectangle {
+ width: 1
+ height: parent.height
+ color: "#04ffffff"
+ }
+ Rectangle {
+ y: parent.height - 1
+ width: parent.width
+ height: 1
+ color: "#80000000"
+ }
+ Rectangle {
+ x: parent.width - 1
+ width: 1
+ height: parent.height
+ color: "#80000000"
+ }
+ }
+}
diff --git a/res/qml/legacy/FxButton.qml b/res/qml/legacy/FxButton.qml
new file mode 100644
index 000000000000..b879273d20ec
--- /dev/null
+++ b/res/qml/legacy/FxButton.qml
@@ -0,0 +1,9 @@
+import QtQuick
+import QtQuick.Controls
+
+ToggleButton {
+ id: control
+ implicitWidth: 18
+ implicitHeight: 18
+ color: control.checked ? "#207000" : "#121212"
+}
diff --git a/res/qml/legacy/FxButtonRow.qml b/res/qml/legacy/FxButtonRow.qml
new file mode 100644
index 000000000000..7aae46bb5fe4
--- /dev/null
+++ b/res/qml/legacy/FxButtonRow.qml
@@ -0,0 +1,19 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+RowLayout {
+ spacing: 0
+ SmallFxButton {
+ text: "FX1"
+ }
+ SmallFxButton {
+ text: "2"
+ }
+ SmallFxButton {
+ text: "3"
+ }
+ SmallFxButton {
+ text: "4"
+ }
+}
diff --git a/res/qml/legacy/FxDial.qml b/res/qml/legacy/FxDial.qml
new file mode 100644
index 000000000000..0bdcd2a5e6e8
--- /dev/null
+++ b/res/qml/legacy/FxDial.qml
@@ -0,0 +1,10 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Dial {
+ from: -1
+ to: 1
+ color: "#35b800"
+}
diff --git a/res/qml/legacy/GainLevel.qml b/res/qml/legacy/GainLevel.qml
new file mode 100644
index 000000000000..5b4a74a377fe
--- /dev/null
+++ b/res/qml/legacy/GainLevel.qml
@@ -0,0 +1,21 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+ColumnLayout {
+ spacing: 0
+
+ E.Dial {
+ from: -1
+ to: 1
+ color: "#c06020"
+ Layout.alignment: Qt.AlignHCenter
+ }
+ E.Slider {
+ orientation: Qt.Vertical
+ backgroundSource: "image://svgmodifier/sliders/level/background.svg"
+ handleSource: "image://svgmodifier/sliders/level/handle.svg"
+ }
+}
diff --git a/res/qml/legacy/HeadphoneMix.qml b/res/qml/legacy/HeadphoneMix.qml
new file mode 100644
index 000000000000..c7d39a08b049
--- /dev/null
+++ b/res/qml/legacy/HeadphoneMix.qml
@@ -0,0 +1,50 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+E.Frame {
+ color: "#171717"
+ padding: 2
+ ColumnLayout {
+ height: parent.height
+ spacing: 2
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter
+ // Headphones
+ ColumnLayout {
+ spacing: 0
+ E.Dial {
+ color: "#c06020"
+ }
+ E.Label {
+ text: "HEAD"
+ Layout.alignment: Qt.AlignHCenter
+ font.pixelSize: 10
+ }
+ }
+ // Mix
+ ColumnLayout {
+ spacing: 0
+ E.Dial {
+ color: "#a00000"
+ }
+ E.Label {
+ text: "MIX"
+ Layout.alignment: Qt.AlignHCenter
+ font.pixelSize: 10
+ }
+ }
+ }
+ E.ToggleButton {
+ text: "SPLIT"
+ font.pixelSize: 12
+ implicitHeight: 20
+ Layout.alignment: Qt.AlignHCenter
+ }
+ E.FxButtonRow {
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+}
diff --git a/res/qml/legacy/IntroOutroButton.qml b/res/qml/legacy/IntroOutroButton.qml
new file mode 100644
index 000000000000..a3107d6d1f72
--- /dev/null
+++ b/res/qml/legacy/IntroOutroButton.qml
@@ -0,0 +1,11 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.ToggleButton {
+ id: control
+ implicitWidth: 24
+ implicitHeight: 24
+ color: checked ? "#257b82" : "#202020"
+}
diff --git a/res/qml/legacy/Label.qml b/res/qml/legacy/Label.qml
new file mode 100644
index 000000000000..a28eba8cbbde
--- /dev/null
+++ b/res/qml/legacy/Label.qml
@@ -0,0 +1,9 @@
+import QtQuick
+import QtQuick.Controls
+
+Text {
+ id: control
+ font.family: "Open Sans"
+ font.bold: true
+ color: "#908070"
+}
diff --git a/res/qml/legacy/LoopButton.qml b/res/qml/legacy/LoopButton.qml
new file mode 100644
index 000000000000..d30e3b98b9f0
--- /dev/null
+++ b/res/qml/legacy/LoopButton.qml
@@ -0,0 +1,9 @@
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ id: control
+ implicitWidth: 24
+ implicitHeight: 24
+ color: pressed ? "#c06020" : "#202020"
+}
diff --git a/res/qml/legacy/LoopToggleButton.qml b/res/qml/legacy/LoopToggleButton.qml
new file mode 100644
index 000000000000..6c351c3b1162
--- /dev/null
+++ b/res/qml/legacy/LoopToggleButton.qml
@@ -0,0 +1,9 @@
+import QtQuick
+import QtQuick.Controls
+
+ToggleButton {
+ id: control
+ implicitWidth: 24
+ implicitHeight: 24
+ color: checked ? "#c06020" : "#202020"
+}
diff --git a/res/qml/legacy/MainMix.qml b/res/qml/legacy/MainMix.qml
new file mode 100644
index 000000000000..205a74861d79
--- /dev/null
+++ b/res/qml/legacy/MainMix.qml
@@ -0,0 +1,46 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+E.Frame {
+ color: "#171717"
+ padding: 2
+ ColumnLayout {
+ height: parent.height
+ spacing: 2
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter
+ // Main
+ ColumnLayout {
+ spacing: 0
+ E.Dial {
+ color: "#c06020"
+ }
+ E.Label {
+ text: "MAIN"
+ Layout.alignment: Qt.AlignHCenter
+ font.pixelSize: 10
+ }
+ }
+ // Balance
+ ColumnLayout {
+ spacing: 0
+ E.Dial {
+ color: "#a00000"
+ from: -1
+ to: 1
+ }
+ E.Label {
+ text: "BAL"
+ Layout.alignment: Qt.AlignHCenter
+ font.pixelSize: 10
+ }
+ }
+ }
+ E.FxButtonRow {
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+}
diff --git a/res/qml/legacy/Mixer.qml b/res/qml/legacy/Mixer.qml
new file mode 100644
index 000000000000..2ef6721e9c83
--- /dev/null
+++ b/res/qml/legacy/Mixer.qml
@@ -0,0 +1,113 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+E.Frame {
+ leftPadding: 4
+ rightPadding: 5
+ color: "#202020"
+ ColumnLayout {
+ height: parent.height
+ spacing: 4
+ RowLayout {
+ Layout.fillHeight: false
+ Layout.alignment: Qt.AlignTop
+ // EQ section left deck
+ E.EqFxSection {
+ }
+ // Gain + Level section left deck
+ E.GainLevel {
+ Layout.alignment: Qt.AlignTop
+ }
+ // PFL + metering
+ ColumnLayout {
+ // PLF section
+ spacing: 0
+ Layout.alignment: Qt.AlignTop
+ RowLayout {
+ spacing: 4
+ Layout.preferredHeight: 36
+ E.PflButton {
+ }
+ E.PflButton {
+ }
+ }
+ Item {
+ implicitHeight: 4
+ }
+ // Metering section
+ RowLayout {
+ spacing: 6
+ Layout.alignment: Qt.AlignHCenter
+ // Meter left deck
+ Rectangle {
+ color: "#606060"
+ implicitWidth: 8
+ Layout.fillHeight: true
+ }
+ // Main output meters
+ RowLayout {
+ spacing: 0
+ Rectangle {
+ color: "#606060"
+ implicitWidth: 8
+ Layout.fillHeight: true
+ }
+ Rectangle {
+ color: "#606060"
+ implicitWidth: 8
+ Layout.fillHeight: true
+ }
+ }
+ // Meter right deck
+ Rectangle {
+ color: "#606060"
+ implicitWidth: 8
+ Layout.fillHeight: true
+ }
+ }
+ Item {
+ implicitHeight: 4
+ }
+ }
+ // Gain + Level section right deck
+ E.GainLevel {
+ Layout.alignment: Qt.AlignTop
+ }
+ // EQ section right deck
+ E.EqFxSection {
+ layoutDirection: Qt.RightToLeft
+ Layout.alignment: Qt.AlignTop
+ }
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ // XFader section
+ RowLayout {
+ Layout.fillWidth: false
+ Layout.alignment: Qt.AlignCenter
+ E.XFaderOrientationSwitch {
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+ Layout.fillWidth: true
+ }
+ E.Slider {
+ implicitWidth: 115
+ implicitHeight: 40
+ from: -1
+ to: 1
+ Layout.columnSpan: 3
+ Layout.alignment: Qt.AlignHCenter
+ backgroundSource: "image://svgmodifier/sliders/xfader/background.svg"
+ handleSource: "image://svgmodifier/sliders/xfader/handle.svg"
+ }
+ E.XFaderOrientationSwitch {
+ Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+ Layout.fillWidth: true
+ value: 2
+ }
+ }
+ }
+}
diff --git a/res/qml/legacy/PflButton.qml b/res/qml/legacy/PflButton.qml
new file mode 100644
index 000000000000..908ff5dba9e0
--- /dev/null
+++ b/res/qml/legacy/PflButton.qml
@@ -0,0 +1,17 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Button {
+ id: control
+ implicitWidth: 24
+ implicitHeight: 24
+ color: control.checked ? "#808080" : "transparent"
+ onPressed: control.toggle()
+ onReleased: {
+ }
+ onClicked: {
+ }
+ icon.source: "image://svgmodifier/icons/pfl.svg?#ff0000/" + (control.checked ? "#000000" : "#908070")
+}
diff --git a/res/qml/legacy/PitchRate.qml b/res/qml/legacy/PitchRate.qml
new file mode 100644
index 000000000000..b082b104c092
--- /dev/null
+++ b/res/qml/legacy/PitchRate.qml
@@ -0,0 +1,61 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "." as E
+
+E.Frame {
+ color: "#202020"
+ padding: 5
+ ColumnLayout {
+ spacing: 0
+ width: parent.width
+ height: parent.height
+ Label {
+ text: "0.00"
+ font.pixelSize: 18
+ padding: 0
+ Layout.alignment: Qt.AlignHCenter
+ }
+ Label {
+ text: "0.00"
+ font.pixelSize: 14
+ padding: 0
+ Layout.alignment: Qt.AlignHCenter
+ }
+ // spacer
+ Item {
+ Layout.fillHeight: true
+ }
+ ToggleButton {
+ text: "SYNC"
+ color: checked ? "#c06020" : "#171717"
+ Layout.alignment: Qt.AlignHCenter
+ }
+ // spacer
+ Item {
+ Layout.fillHeight: true
+ }
+ RowLayout {
+ Layout.fillHeight: false
+ Slider {
+ from: -8
+ to: 8
+ orientation: Qt.Vertical
+ backgroundSource: "image://svgmodifier/sliders/pitchrate/background.svg"
+ handleSource: "image://svgmodifier/sliders/pitchrate/handle.svg"
+ }
+ ColumnLayout {
+ spacing: 2
+ PitchRateButton {
+ }
+ PitchRateButton {
+ }
+ PitchRateButton {
+ }
+ PitchRateButton {
+ }
+ }
+ }
+ }
+}
diff --git a/res/qml/legacy/PitchRateButton.qml b/res/qml/legacy/PitchRateButton.qml
new file mode 100644
index 000000000000..d30e3b98b9f0
--- /dev/null
+++ b/res/qml/legacy/PitchRateButton.qml
@@ -0,0 +1,9 @@
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ id: control
+ implicitWidth: 24
+ implicitHeight: 24
+ color: pressed ? "#c06020" : "#202020"
+}
diff --git a/res/qml/legacy/Slider.qml b/res/qml/legacy/Slider.qml
new file mode 100644
index 000000000000..9b7be7d5ce7a
--- /dev/null
+++ b/res/qml/legacy/Slider.qml
@@ -0,0 +1,40 @@
+import QtQuick
+import QtQuick.Controls
+
+Slider {
+ id: control
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: 0
+ bottomPadding: 0
+ implicitWidth: implicitBackgroundWidth
+ implicitHeight: implicitBackgroundHeight
+
+ property url backgroundSource
+ property url handleSource
+
+ background: Image {
+ source: backgroundSource
+ Rectangle {
+ readonly property real offset: horizontal ? control.leftPadding + 6 : control.topPadding + 6
+ readonly property real extreme: horizontal ? control.leftPadding + 6 : control.height - control.bottomPadding - 6
+ readonly property real center: horizontal ? control.width / 2 : control.height / 2
+ readonly property real range: horizontal ? control.availableWidth - 12 : control.availableHeight - 12
+ readonly property real trackFrom: control.from === -control.to ? center : extreme
+ readonly property real trackTo: offset + control.visualPosition * range
+ readonly property real trackMin: trackFrom < trackTo ? trackFrom : trackTo
+ readonly property real trackMax: trackFrom > trackTo ? trackFrom : trackTo
+ color: "#257b82"
+ x: horizontal ? trackMin : (control.width - width) / 2
+ y: vertical ? trackMin : (control.height - height) / 2
+ width: horizontal ? trackMax - trackMin : 2
+ height: vertical ? trackMax - trackMin : 2
+ }
+ }
+
+ handle: Image {
+ source: handleSource
+ x: horizontal ? control.leftPadding + control.visualPosition * (control.availableWidth - width) : control.leftPadding + control.availableWidth / 2 - width / 2
+ y: vertical ? control.topPadding + control.visualPosition * (control.availableHeight - height) : control.topPadding + control.availableHeight / 2 - height / 2
+ }
+}
diff --git a/res/qml/legacy/SmallFxButton.qml b/res/qml/legacy/SmallFxButton.qml
new file mode 100644
index 000000000000..d17750112189
--- /dev/null
+++ b/res/qml/legacy/SmallFxButton.qml
@@ -0,0 +1,12 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ToggleButton {
+ id: control
+ leftPadding: 3
+ rightPadding: 3
+ implicitHeight: 20
+ font.pixelSize: 12
+ color: control.checked ? "#207000" : "#121212"
+}
diff --git a/res/qml/legacy/SpinBox.qml b/res/qml/legacy/SpinBox.qml
new file mode 100644
index 000000000000..5ce6d85ece02
--- /dev/null
+++ b/res/qml/legacy/SpinBox.qml
@@ -0,0 +1,127 @@
+import QtQuick
+import QtQuick.Controls
+
+SpinBox {
+ id: control
+ property color color: "#202020"
+ implicitHeight: 24
+ implicitWidth: 56
+ leftPadding: 2
+ rightPadding: 22
+ topPadding: 2
+ bottomPadding: 2
+ font.bold: true
+
+ background: Rectangle {
+ color: "#000000"
+ Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 20
+ height: parent.height - 2
+ color: control.color
+ radius: 2
+ Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: "#60000000"
+ radius: 2
+ }
+ Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: 1
+ color: "#000000"
+ }
+ Rectangle {
+ x: 1
+ y: 1
+ width: 1
+ height: parent.height - 2
+ color: "#000000"
+ }
+ }
+ Rectangle {
+ x: parent.width - 20
+ y: 0
+ width: 1
+ height: parent.height
+ color: "#000000"
+ }
+ Rectangle {
+ x: parent.width - 20
+ y: 1
+ width: 20 - 1
+ height: parent.height - 2
+ color: control.color
+ radius: 2
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ border.color: control.pressed ? "#60000000" : "#04ffffff"
+ border.width: 1
+ radius: 2
+ }
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: control.pressed ? "#04ffffff" : "#0cffffff"
+ }
+ }
+ }
+
+ up.indicator: Rectangle {
+ x: parent.width - 19
+ y: 1
+ width: 18
+ height: 11
+ radius: 2
+ color: control.up.pressed ? "#257b82" : "transparent"
+ Image {
+ source: "assets/spinbox/indicator_up.svg"
+ }
+ }
+
+ down.indicator: Rectangle {
+ x: parent.width - 19
+ y: parent.height / 2
+ width: 18
+ height: 11
+ radius: 2
+ color: control.down.pressed ? "#257b82" : "transparent"
+ Image {
+ source: "assets/spinbox/indicator_down.svg"
+ }
+ }
+
+ contentItem: TextInput {
+ text: control.textFromValue(control.value, control.locale)
+ font: control.font
+ color: "#908070"
+ selectionColor: "#257b82"
+ selectedTextColor: "#ffffff"
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: Qt.ImhFormattedNumbersOnly
+
+ onAccepted: control.focus = false
+
+ Rectangle {
+ x: 0
+ y: 0
+ visible: control.activeFocus
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ border.color: "#257b82"
+ border.width: 1
+ }
+ }
+}
diff --git a/res/qml/legacy/ToggleButton.qml b/res/qml/legacy/ToggleButton.qml
new file mode 100644
index 000000000000..816f6563e177
--- /dev/null
+++ b/res/qml/legacy/ToggleButton.qml
@@ -0,0 +1,14 @@
+import QtQuick
+import QtQuick.Controls
+
+import "." as E
+
+E.Button {
+ id: control
+ color: checked ? "#808080" : "#202020"
+ onPressed: control.toggle()
+ onReleased: {
+ }
+ onClicked: {
+ }
+}
diff --git a/res/qml/legacy/XFaderOrientationSwitch.qml b/res/qml/legacy/XFaderOrientationSwitch.qml
new file mode 100644
index 000000000000..bcd0f0fcf018
--- /dev/null
+++ b/res/qml/legacy/XFaderOrientationSwitch.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.Controls
+
+Control {
+ id: control
+ property int value: 0
+ padding: 0
+ background: Rectangle {
+ color: "#000000"
+ radius: control.height / 2
+ }
+ contentItem: Item {
+ implicitWidth: 32
+ implicitHeight: 8
+ Image {
+ x: value * (contentItem.width - contentItem.height) / 2
+ width: control.height
+ height: control.height
+ source: "image://svgmodifier/xfader_orientation/handle.svg"
+ }
+ }
+ Binding on value {
+ when: mouse.pressed
+ value: Math.max(0, Math.min(2, 2 * mouse.mouseX / control.width))
+ restoreMode: Binding.RestoreBinding
+ }
+ MouseArea {
+ id: mouse
+ width: control.width
+ height: control.height
+ }
+}
diff --git a/res/qml/legacy/assets/dial/background.svg b/res/qml/legacy/assets/dial/background.svg
new file mode 100644
index 000000000000..32eb722cc7f4
--- /dev/null
+++ b/res/qml/legacy/assets/dial/background.svg
@@ -0,0 +1,14 @@
+
+
diff --git a/res/qml/legacy/assets/dial/foreground.svg b/res/qml/legacy/assets/dial/foreground.svg
new file mode 100644
index 000000000000..51f961eadd54
--- /dev/null
+++ b/res/qml/legacy/assets/dial/foreground.svg
@@ -0,0 +1,99 @@
+
+
diff --git a/res/qml/legacy/assets/dial/handle.svg b/res/qml/legacy/assets/dial/handle.svg
new file mode 100644
index 000000000000..4f4e444c55ca
--- /dev/null
+++ b/res/qml/legacy/assets/dial/handle.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/res/qml/legacy/assets/dial/track.svg b/res/qml/legacy/assets/dial/track.svg
new file mode 100644
index 000000000000..c5dc8a5cffb3
--- /dev/null
+++ b/res/qml/legacy/assets/dial/track.svg
@@ -0,0 +1,15 @@
+
+
diff --git a/res/qml/legacy/assets/fonts/OpenSans-Bold.ttf b/res/qml/legacy/assets/fonts/OpenSans-Bold.ttf
new file mode 100644
index 000000000000..fd79d43bea02
Binary files /dev/null and b/res/qml/legacy/assets/fonts/OpenSans-Bold.ttf differ
diff --git a/res/qml/legacy/assets/fonts/OpenSans-Regular.ttf b/res/qml/legacy/assets/fonts/OpenSans-Regular.ttf
new file mode 100644
index 000000000000..db433349b704
Binary files /dev/null and b/res/qml/legacy/assets/fonts/OpenSans-Regular.ttf differ
diff --git a/res/qml/legacy/assets/fonts/OpenSans-Semibold.ttf b/res/qml/legacy/assets/fonts/OpenSans-Semibold.ttf
new file mode 100644
index 000000000000..1a7679e3949f
Binary files /dev/null and b/res/qml/legacy/assets/fonts/OpenSans-Semibold.ttf differ
diff --git a/res/qml/legacy/assets/fonts/OpenSans.LICENSE.txt b/res/qml/legacy/assets/fonts/OpenSans.LICENSE.txt
new file mode 100644
index 000000000000..75b52484ea47
--- /dev/null
+++ b/res/qml/legacy/assets/fonts/OpenSans.LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/res/qml/legacy/assets/icons/pfl.svg b/res/qml/legacy/assets/icons/pfl.svg
new file mode 100644
index 000000000000..9c4490359b34
--- /dev/null
+++ b/res/qml/legacy/assets/icons/pfl.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/res/qml/legacy/assets/sliders/level/background.svg b/res/qml/legacy/assets/sliders/level/background.svg
new file mode 100644
index 000000000000..86e8a7b3c16b
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/level/background.svg
@@ -0,0 +1,43 @@
+
diff --git a/res/qml/legacy/assets/sliders/level/handle.svg b/res/qml/legacy/assets/sliders/level/handle.svg
new file mode 100644
index 000000000000..c8e7037d9cd4
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/level/handle.svg
@@ -0,0 +1,18 @@
+
diff --git a/res/qml/legacy/assets/sliders/pitchrate/background.svg b/res/qml/legacy/assets/sliders/pitchrate/background.svg
new file mode 100644
index 000000000000..c82d88445747
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/pitchrate/background.svg
@@ -0,0 +1,39 @@
+
diff --git a/res/qml/legacy/assets/sliders/pitchrate/handle.svg b/res/qml/legacy/assets/sliders/pitchrate/handle.svg
new file mode 100644
index 000000000000..c8e7037d9cd4
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/pitchrate/handle.svg
@@ -0,0 +1,18 @@
+
diff --git a/res/qml/legacy/assets/sliders/xfader/background.svg b/res/qml/legacy/assets/sliders/xfader/background.svg
new file mode 100644
index 000000000000..5ac6e3a81171
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/xfader/background.svg
@@ -0,0 +1,164 @@
+
+
diff --git a/res/qml/legacy/assets/sliders/xfader/handle.svg b/res/qml/legacy/assets/sliders/xfader/handle.svg
new file mode 100644
index 000000000000..0028c316265b
--- /dev/null
+++ b/res/qml/legacy/assets/sliders/xfader/handle.svg
@@ -0,0 +1,98 @@
+
+
diff --git a/res/qml/legacy/assets/spinbox/indicator_down.svg b/res/qml/legacy/assets/spinbox/indicator_down.svg
new file mode 100644
index 000000000000..06b084574a9b
--- /dev/null
+++ b/res/qml/legacy/assets/spinbox/indicator_down.svg
@@ -0,0 +1,77 @@
+
+
diff --git a/res/qml/legacy/assets/spinbox/indicator_up.svg b/res/qml/legacy/assets/spinbox/indicator_up.svg
new file mode 100644
index 000000000000..3564bd63d062
--- /dev/null
+++ b/res/qml/legacy/assets/spinbox/indicator_up.svg
@@ -0,0 +1,45 @@
+
+
diff --git a/res/qml/legacy/assets/xfader_orientation/handle.svg b/res/qml/legacy/assets/xfader_orientation/handle.svg
new file mode 100644
index 000000000000..f7b2bfcd11d7
--- /dev/null
+++ b/res/qml/legacy/assets/xfader_orientation/handle.svg
@@ -0,0 +1,58 @@
+
+
+
+
diff --git a/res/skins/LateNight/mixer.xml b/res/skins/LateNight/mixer.xml
index 35dbedd49843..f1903c6a8561 100644
--- a/res/skins/LateNight/mixer.xml
+++ b/res/skins/LateNight/mixer.xml
@@ -1,72 +1,11 @@
-
-
-
+
max,me
horizontal
-
-
-
- MixerContainer
- min,me
- horizontal
-
-
-
- MixerDecks
- max,min
- vertical
-
-
-
-
-
- [Skin],show_main_head_mixer
- highlight
-
-
-
-
-
-
-
-
-
+ CenterMixerComponent.qml
[Skin],show_mixer
visible
-
-
-
- max,me
- horizontal
-
-
-
-
- min,me
- vertical
-
-
-
- CompactDecksCenterSpacer
-
-
-
-
-
-
- [LateNight],show_compact_deck
- visible
-
-
-
-
-
- [Skin],show_mixer
-
- visible
-
-
+
diff --git a/src/coreservices.cpp b/src/coreservices.cpp
index 045f900a4367..832c2fe4c564 100644
--- a/src/coreservices.cpp
+++ b/src/coreservices.cpp
@@ -350,8 +350,9 @@ inline QLocale inputLocale() {
namespace mixxx {
-CoreServices::CoreServices(const CmdlineArgs& args, QApplication* pApp)
- : m_runtime_timer(QLatin1String("CoreServices::runtime")),
+CoreServices::CoreServices(const CmdlineArgs& args, QApplication* pApp, QQmlEngine* pQmlEngine)
+ : m_pQmlEngine(pQmlEngine),
+ m_runtime_timer(QLatin1String("CoreServices::runtime")),
m_cmdlineArgs(args),
m_isInitialized(false) {
m_runtime_timer.start();
diff --git a/src/coreservices.h b/src/coreservices.h
index f0f78baf4184..fdc10a7a8128 100644
--- a/src/coreservices.h
+++ b/src/coreservices.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
#include
#include "preferences/settingsmanager.h"
@@ -34,7 +36,7 @@ class CoreServices : public QObject {
Q_OBJECT
public:
- CoreServices(const CmdlineArgs& args, QApplication* pApp);
+ CoreServices(const CmdlineArgs& args, QApplication* pApp, QQmlEngine* pQmlEngine);
~CoreServices();
/// The secondary long run which should be called after displaying the start up screen
@@ -104,6 +106,10 @@ class CoreServices : public QObject {
std::shared_ptr makeDlgPreferences() const;
+ QQmlEngine* getQmlEngine() {
+ return m_pQmlEngine;
+ }
+
signals:
void initializationProgressUpdate(int progress, const QString& serviceName);
void libraryScanSummary(const LibraryScanResultSummary& result);
@@ -124,6 +130,7 @@ class CoreServices : public QObject {
/// Tear down CoreServices that were previously initialized by `initialize()`.
void finalize();
+ QQmlEngine* m_pQmlEngine;
std::shared_ptr m_pSettingsManager;
std::shared_ptr m_pControlIndicatorTimer;
std::shared_ptr m_pEffectsManager;
diff --git a/src/main.cpp b/src/main.cpp
index acb15b80e57f..330eb32f594b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -60,14 +60,15 @@ int runMixxx(MixxxApplication* pApp, const CmdlineArgs& args) {
CmdlineArgs::Instance().parseForUserFeedback();
int exitCode;
-#ifdef MIXXX_USE_QML
- if (args.isQml()) {
- mixxx::qml::QmlApplication qmlApplication(pApp, args);
- exitCode = pApp->exec();
- } else
-#endif
+ // #ifdef MIXXX_USE_QML
+ // if (args.isQml()) {
+ mixxx::qml::QmlApplication qmlApplication(pApp, args);
+ // exitCode = pApp->exec();
+ // } else
+ // #endif
{
- auto pCoreServices = std::make_shared(args, pApp);
+ auto pCoreServices = std::make_shared(
+ args, pApp, qmlApplication.engine());
// This scope ensures that `MixxxMainWindow` is destroyed *before*
// CoreServices is shut down. Otherwise a debug assertion complaining about
diff --git a/src/mixxxmainwindow.cpp b/src/mixxxmainwindow.cpp
index e35b53ab5910..ab57bffeca6b 100644
--- a/src/mixxxmainwindow.cpp
+++ b/src/mixxxmainwindow.cpp
@@ -1,5 +1,7 @@
#include "mixxxmainwindow.h"
+#include
+
#include
#include
#include
@@ -141,7 +143,8 @@ MixxxMainWindow::MixxxMainWindow(std::shared_ptr pCoreServi
// Show launch image immediately so the user knows Mixxx is starting
m_pSkinLoader = std::make_unique(m_pCoreServices->getSettings());
m_pLaunchImage = m_pSkinLoader->loadLaunchImage(this);
- m_pCentralWidget = (QWidget*)m_pLaunchImage;
+ m_pCentralWidget = new QQuickWidget(m_pCoreServices->getQmlEngine(), this);
+ ;
setCentralWidget(m_pCentralWidget);
show();
diff --git a/src/mixxxmainwindow.h b/src/mixxxmainwindow.h
index 4a26a43aefd7..29781f170a31 100644
--- a/src/mixxxmainwindow.h
+++ b/src/mixxxmainwindow.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
#include
#include
#include
diff --git a/src/qml/qmlapplication.cpp b/src/qml/qmlapplication.cpp
index 062164021d9c..44caef33c332 100644
--- a/src/qml/qmlapplication.cpp
+++ b/src/qml/qmlapplication.cpp
@@ -1,5 +1,8 @@
#include "qmlapplication.h"
+#include
+#include
+
#include
#include
@@ -26,6 +29,55 @@ auto lambda_to_singleton_type_factory_ptr(F&& f) {
return fn(pEngine, pScriptEngine);
};
}
+
+// image provider that allows to search/replace colors in the svg file before rendering it
+class SvgModifierImageProvider : public QQuickImageProvider {
+ public:
+ SvgModifierImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Pixmap) {
+ }
+
+ QPixmap requestPixmap(const QString& rid, QSize* size, const QSize& requestedSize) override {
+ const QStringList list = rid.split("?");
+ const QString resourceId(list.length() > 0 ? list[0] : QString());
+ const QStringList mods(list.length() > 1 ? list[1].split("+") : QStringList());
+ QFile resource("../res/qml/legacy/assets/" + resourceId);
+ resource.open(QIODevice::ReadOnly);
+ QByteArray data = resource.readAll();
+
+ for (const auto mod : mods) {
+ QStringList ab = mod.split("/");
+ if (ab.length() == 2) {
+ data.replace(ab[0].toLatin1(), ab[1].toLatin1());
+ }
+ }
+
+ QSvgRenderer renderer(data);
+
+ // TODO is this the right way?
+ const auto devicePixelRatio = QGuiApplication::primaryScreen()->devicePixelRatio();
+
+ int width = renderer.defaultSize().width() * devicePixelRatio;
+ int height = renderer.defaultSize().height() * devicePixelRatio;
+
+ if (size)
+ *size = QSize(width, height);
+ QPixmap pixmap(requestedSize.width() * devicePixelRatio > 0
+ ? requestedSize.width() * devicePixelRatio
+ : width,
+ requestedSize.height() * devicePixelRatio > 0
+ ? requestedSize.height() * devicePixelRatio
+ : height);
+
+ pixmap.fill(QColor("transparent"));
+ QPainter painter(&pixmap);
+ renderer.render(&painter, pixmap.rect());
+
+ pixmap.setDevicePixelRatio(devicePixelRatio);
+
+ return pixmap;
+ }
+};
} // namespace
namespace mixxx {
@@ -34,60 +86,60 @@ namespace qml {
QmlApplication::QmlApplication(
QApplication* app,
const CmdlineArgs& args)
- : m_pCoreServices(std::make_unique(args, app)),
+ : m_pCoreServices(std::make_unique(args, app, engine())),
m_visualsManager(std::make_unique()),
m_mainFilePath(m_pCoreServices->getSettings()->getResourcePath() + kMainQmlFileName),
m_pAppEngine(nullptr),
m_autoReload() {
QQuickStyle::setStyle("Basic");
- m_pCoreServices->initialize(app);
- SoundDeviceStatus result = m_pCoreServices->getSoundManager()->setupDevices();
- if (result != SoundDeviceStatus::Ok) {
- const int reInt = static_cast(result);
- qCritical() << "Error setting up sound devices:" << reInt;
- exit(reInt);
- }
-
- // FIXME: DlgPreferences has some initialization logic that must be executed
- // before the GUI is shown, at least for the effects system.
- std::shared_ptr pDlgPreferences = m_pCoreServices->makeDlgPreferences();
- // Without this, QApplication will quit when the last QWidget QWindow is
- // closed because it does not take into account the window created by
- // the QQmlApplicationEngine.
- pDlgPreferences->setAttribute(Qt::WA_QuitOnClose, false);
-
- // Since DlgPreferences is only meant to be used in the main QML engine, it
- // follows a strict singleton pattern design
- QmlDlgPreferencesProxy::s_pInstance =
- std::make_unique(pDlgPreferences, this);
+ // m_pCoreServices->initialize(app);
+ // SoundDeviceStatus result = m_pCoreServices->getSoundManager()->setupDevices();
+ // if (result != SoundDeviceStatus::Ok) {
+ // const int reInt = static_cast(result);
+ // qCritical() << "Error setting up sound devices:" << reInt;
+ // exit(reInt);
+ // }
+
+ // // FIXME: DlgPreferences has some initialization logic that must be executed
+ // // before the GUI is shown, at least for the effects system.
+ // std::shared_ptr pDlgPreferences = m_pCoreServices->makeDlgPreferences();
+ // // Without this, QApplication will quit when the last QWidget QWindow is
+ // // closed because it does not take into account the window created by
+ // // the QQmlApplicationEngine.
+ // pDlgPreferences->setAttribute(Qt::WA_QuitOnClose, false);
+
+ // // Since DlgPreferences is only meant to be used in the main QML engine, it
+ // // follows a strict singleton pattern design
+ // QmlDlgPreferencesProxy::s_pInstance =
+ // std::make_unique(pDlgPreferences, this);
loadQml(m_mainFilePath);
- m_pCoreServices->getControllerManager()->setUpDevices();
-
- connect(&m_autoReload,
- &QmlAutoReload::triggered,
- this,
- [this]() {
- loadQml(m_mainFilePath);
- });
-
- const QStringList visualGroups =
- m_pCoreServices->getPlayerManager()->getVisualPlayerGroups();
- for (const QString& group : visualGroups) {
- m_visualsManager->addDeck(group);
- }
-
- m_pCoreServices->getPlayerManager()->connect(
- m_pCoreServices->getPlayerManager().get(),
- &PlayerManager::numberOfDecksChanged,
- this,
- [this](int decks) {
- for (int i = 0; i < decks; ++i) {
- QString group = PlayerManager::groupForDeck(i);
- m_visualsManager->addDeckIfNotExist(group);
- }
- });
+ // m_pCoreServices->getControllerManager()->setUpDevices();
+
+ // connect(&m_autoReload,
+ // &QmlAutoReload::triggered,
+ // this,
+ // [this]() {
+ // loadQml(m_mainFilePath);
+ // });
+
+ // const QStringList visualGroups =
+ // m_pCoreServices->getPlayerManager()->getVisualPlayerGroups();
+ // for (const QString& group : visualGroups) {
+ // m_visualsManager->addDeck(group);
+ // }
+
+ // m_pCoreServices->getPlayerManager()->connect(
+ // m_pCoreServices->getPlayerManager().get(),
+ // &PlayerManager::numberOfDecksChanged,
+ // this,
+ // [this](int decks) {
+ // for (int i = 0; i < decks; ++i) {
+ // QString group = PlayerManager::groupForDeck(i);
+ // m_visualsManager->addDeckIfNotExist(group);
+ // }
+ // });
}
QmlApplication::~QmlApplication() {
@@ -111,11 +163,12 @@ void QmlApplication::loadQml(const QString& path) {
QQuickAsyncImageProvider* pImageProvider = new AsyncImageProvider(
m_pCoreServices->getTrackCollectionManager());
m_pAppEngine->addImageProvider(AsyncImageProvider::kProviderName, pImageProvider);
+ m_pAppEngine->addImageProvider(QString("svgmodifier"), new SvgModifierImageProvider);
- m_pAppEngine->load(path);
- if (m_pAppEngine->rootObjects().isEmpty()) {
- qCritical() << "Failed to load QML file" << path;
- }
+ // m_pAppEngine->load(path);
+ // if (m_pAppEngine->rootObjects().isEmpty()) {
+ // qCritical() << "Failed to load QML file" << path;
+ // }
}
} // namespace qml
diff --git a/src/qml/qmlapplication.h b/src/qml/qmlapplication.h
index 8b63ba835a4d..f2cb9eb813cb 100644
--- a/src/qml/qmlapplication.h
+++ b/src/qml/qmlapplication.h
@@ -20,6 +20,9 @@ class QmlApplication : public QObject {
const CmdlineArgs& args);
~QmlApplication() override;
+ QQmlEngine* engine() {
+ return m_pAppEngine.get();
+ }
public slots:
void loadQml(const QString& path);
diff --git a/src/skin/legacy/legacyskin.cpp b/src/skin/legacy/legacyskin.cpp
index f3289f245130..6869834a24ae 100644
--- a/src/skin/legacy/legacyskin.cpp
+++ b/src/skin/legacy/legacyskin.cpp
@@ -140,7 +140,8 @@ QWidget* LegacySkin::loadSkin(QWidget* pParent,
pCoreServices->getLibrary().get(),
pCoreServices->getVinylControlManager().get(),
pCoreServices->getEffectsManager().get(),
- pCoreServices->getRecordingManager().get());
+ pCoreServices->getRecordingManager().get(),
+ pCoreServices->getQmlEngine());
return legacy.parseSkin(m_path.absoluteFilePath(), pParent);
}
diff --git a/src/skin/legacy/legacyskinparser.cpp b/src/skin/legacy/legacyskinparser.cpp
index 2e0951b3961a..2d9da963e5d0 100644
--- a/src/skin/legacy/legacyskinparser.cpp
+++ b/src/skin/legacy/legacyskinparser.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -182,7 +183,8 @@ LegacySkinParser::LegacySkinParser(UserSettingsPointer pConfig,
Library* pLibrary,
VinylControlManager* pVCMan,
EffectsManager* pEffectsManager,
- RecordingManager* pRecordingManager)
+ RecordingManager* pRecordingManager,
+ QQmlEngine* pQmlEngine)
: m_pConfig(pConfig),
m_pSkinCreatedControls(pSkinCreatedControls),
m_pKeyboard(pKeyboard),
@@ -192,6 +194,7 @@ LegacySkinParser::LegacySkinParser(UserSettingsPointer pConfig,
m_pVCManager(pVCMan),
m_pEffectsManager(pEffectsManager),
m_pRecordingManager(pRecordingManager),
+ m_pQmlEngine(pQmlEngine),
m_pParent(nullptr) {
DEBUG_ASSERT(m_pSkinCreatedControls);
}
@@ -649,6 +652,15 @@ QList LegacySkinParser::parseNode(const QDomElement& node) {
parseSingletonDefinition(node);
} else if (nodeName == "SingletonContainer") {
result = wrapWidget(parseStandardWidget(node));
+ } else if (nodeName == "QML") {
+ auto* pWidget = new QQuickWidget(m_pQmlEngine, m_pParent);
+ pWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QString scene = m_pContext->selectString(node, "Scene");
+ pWidget->setSource(QUrl::fromLocalFile("../res/qml/legacy/" + scene));
+ setupWidget(node, pWidget);
+ // auto *pWWidget = new WBaseWidget(pWidget);
+ // setupConnections(node, pWWidget);
+ result = wrapWidget(pWidget);
} else {
SKIN_WARNING(node,
*m_pContext,
diff --git a/src/skin/legacy/legacyskinparser.h b/src/skin/legacy/legacyskinparser.h
index 54d21aa38bd5..308cf6cf12f0 100644
--- a/src/skin/legacy/legacyskinparser.h
+++ b/src/skin/legacy/legacyskinparser.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
#include
#include
#include
@@ -39,7 +41,8 @@ class LegacySkinParser : public QObject, public SkinParser {
Library* pLibrary,
VinylControlManager* pVCMan,
EffectsManager* pEffectsManager,
- RecordingManager* pRecordingManager);
+ RecordingManager* pRecordingManager,
+ QQmlEngine* pQmlEngine);
virtual ~LegacySkinParser();
virtual bool canParse(const QString& skinPath);
@@ -169,6 +172,7 @@ class LegacySkinParser : public QObject, public SkinParser {
VinylControlManager* m_pVCManager;
EffectsManager* m_pEffectsManager;
RecordingManager* m_pRecordingManager;
+ QQmlEngine* m_pQmlEngine;
QWidget* m_pParent;
std::unique_ptr m_pContext;
QString m_style;
diff --git a/src/skin/skinloader.h b/src/skin/skinloader.h
index d306204fca73..3125d7909457 100644
--- a/src/skin/skinloader.h
+++ b/src/skin/skinloader.h
@@ -1,5 +1,7 @@
#pragma once
+#include
+
#include
#include
#include
@@ -42,6 +44,7 @@ class SkinLoader : public QObject {
SkinPointer skinFromDirectory(const QDir& dir) const;
UserSettingsPointer m_pConfig;
+ QQmlEngine* m_pQmlEngine;
bool m_spinnyCoverControlsCreated;
void setupSpinnyCoverControls();