diff options
Diffstat (limited to 'src/clapcontrols/ClapDial.qml')
| -rw-r--r-- | src/clapcontrols/ClapDial.qml | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/clapcontrols/ClapDial.qml b/src/clapcontrols/ClapDial.qml new file mode 100644 index 0000000..771f9cb --- /dev/null +++ b/src/clapcontrols/ClapDial.qml @@ -0,0 +1,237 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Qt-Commercial + +import QtQml +import QtQuick +import QtQuick.Controls.Basic +import QtQuick.Shapes + +import Clap.Interface +import Clap.Controls + +Dial { + id: ctrl + Keys.onLeftPressed: {} + required property int paramId + property var param + property var paramInfo + property real modulation: 0 + + property bool modulationEnabled: false + property real defaultValue: range / 2 + property bool inverted: false + property int textPrecision: 2 + property int precisionMultiplier: 10 + property string valueType: "dB" + + readonly property color cBg: QClapStyle.color("bg2") + readonly property color cFg: QClapStyle.color("fg") + readonly property color cBorder: QClapStyle.color("bg0_h") + readonly property color cParam: QClapStyle.color("fg3") + readonly property color cMod: QClapStyle.color("orange") + readonly property color cNormal: QClapStyle.color("transparent") + property color cBgNormal: Qt.tint(cBg, cNormal) + property color cFgNormal: Qt.tint(cFg, cNormal) + property color cBorderNormal: Qt.tint(cBorder, cNormal) + property color cParamNormal: Qt.tint(cParam, cNormal) + property color cModNormal: Qt.tint(cMod, cNormal) + + readonly property color cDisabled: "red" + property color cBgDisabled: Qt.tint(cBg, cDisabled) + property color cFgDisabled: Qt.tint(cFg, cDisabled) + property color cBorderDisabled: Qt.tint(cBorder, cDisabled) + property color cParamDisabled: Qt.tint(cParam, cDisabled) + property color cModDisabled: Qt.tint(cMod, cDisabled) + + readonly property real range: Math.abs(from - to) + readonly property int size: ctrl.background.width + readonly property real center: size / 2 + readonly property real borderWidth: size * 0.13 + readonly property real modulationAngle: (modulation - (-80)) * (520 - (-260)) / (80 - (-80)) + (-260) + readonly property real startAnglePos: 130 + property bool precisionMode: false + + Connections { + target: ClapInterface + function onParamChanged() { + ctrl.param = ClapInterface.param(paramId); + ctrl.value = ctrl.param.value; + ctrl.modulation = ctrl.param.modulation; + } + function onParamInfoChanged() { + ctrl.paramInfo = ClapInterface.paramInfo(paramId); + ctrl.value = ctrl.paramInfo.defaultValue; + ctrl.from = ctrl.paramInfo.minValue; + ctrl.to = ctrl.paramInfo.maxValue; + } + function onStateChanged() { + switch(ClapInterface.state) { + case ClapInterface.Active: { + ctrl.enabled = true; + break; + } + case ClapInterface.Inactive: { + ctrl.enabled = false; + break; + } + } + } + } + + onValueChanged: { + if (ctrl.pressed || ctrl.hovered) { + ClapInterface.enqueueParam(ctrl.paramId, ctrl.value); + } + } + + function clamp(val, min, max) { + return Math.min(Math.max(val, min), max); + } + + enum ColorType { Bg, Fg, Border, Param, Mod } + function activeColor(type) { + switch(type) { + case ClapDial.ColorType.Bg: { + return !ctrl.enabled ? ctrl.cBgDisabled : ctrl.cBg + } + case ClapDial.ColorType.Fg: { + return !ctrl.enabled ? ctrl.cFgDisabled : + !ctrl.precisionMode ? ctrl.cFg : QClapStyle.color("yellow2") + } + case ClapDial.ColorType.Border: { + return !ctrl.enabled ? ctrl.cBorderDisabled : ctrl.cBorder + } + case ClapDial.ColorType.Param: { + return !ctrl.enabled ? ctrl.cParamDisabled : ctrl.cParam + } + case ClapDial.ColorType.Mod: { + return !ctrl.modulationEnabled ? "transparent" : + !ctrl.enabled ? ctrl.cModDisabled : + !(ctrl.hovered | ctrl.activeFocus) ? ctrl.cModNormal + : ctrl.cMod + } + } + } + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding) + + // Keys.onLeftPressed: {} + stepSize: range / 20 + inputMode: Dial.Vertical + focusPolicy: Qt.WheelFocus + padding: 10 + wheelEnabled: true + focus: true + startAngle: 0 + endAngle: 280 + enabled: true + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 100 + + width: Math.max(64, Math.min(ctrl.width, ctrl.height)) + height: width + + x: ctrl.width / 2 - width / 2 + y: ctrl.height / 2 - height / 2 + + radius: width / 2 + color: ctrl.activeColor(ClapDial.ColorType.Bg) + border.color: ctrl.activeColor(ClapDial.ColorType.Border) + border.width: ctrl.borderWidth + antialiasing: true + + Text { + anchors.centerIn: parent + font.pointSize: ctrl.size * 0.1 + text: !ctrl.precisionMode ? ctrl.value.toFixed(ctrl.textPrecision) + ' ' + ctrl.valueType + : ctrl.value.toFixed(4) + color: ctrl.activeColor(ClapDial.ColorType.Fg) + } + } // background + + handle: Shape { + z: 1 + implicitWidth: ctrl.background.width + implicitHeight: ctrl.background.height + x: ctrl.background.x + y: ctrl.background.y + layer.enabled: true + layer.samples: 4 + antialiasing: true + + component ParamIndication: ShapePath { + id: indication + + required property real range + required property real borderAmount + property real offset: 0 + property real start: ctrl.startAnglePos + readonly property real radius: (ctrl.background.width / 2) - (borderAmount / 2) - offset + + capStyle: ShapePath.FlatCap + fillColor: "transparent" + strokeWidth: borderAmount + + PathAngleArc { + centerX: ctrl.center + centerY: ctrl.center + radiusX: indication.radius + radiusY: radiusX + startAngle: indication.start + sweepAngle: indication.range + } + } + + ParamIndication { // Parameter Value + range: ctrl.angle + borderAmount: ctrl.borderWidth + 1 + strokeColor: ctrl.activeColor(ClapDial.ColorType.Param) + } + + ParamIndication { // Parameter Modulation + range: ctrl.modulationAngle + borderAmount: ctrl.borderWidth * 0.5 + strokeColor: ctrl.activeColor(ClapDial.ColorType.Mod) + offset: borderAmount + 1 + } + } + + Keys.onPressed: (event) => { + if (event.key === Qt.Key_Shift) { + ctrl.precisionMode = true; + } + } + Keys.onReleased: (event) => { + if (event.key === Qt.Key_Shift) { + ctrl.precisionMode = false; + } + } + + // NormalMode + WheelHandler { + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + acceptedModifiers: Qt.NoModifier + cursorShape: Qt.DragMoveCursor + onWheel: (wev) => { + let delta = (wev.angleDelta.y / 120) * ctrl.stepSize; + let v = !ctrl.inverted ? ctrl.value + delta : ctrl.value - delta; + ctrl.value = ctrl.clamp(ctrl.from, v, ctrl.to); + } + } + // PrecisionMode + WheelHandler { + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + acceptedModifiers: Qt.ShiftModifier + cursorShape: Qt.DragMoveCursor + onWheel: (wev) => { + let delta = (wev.angleDelta.y / (120 * 10)) * ctrl.stepSize; + let v = !ctrl.inverted ? ctrl.value + delta : ctrl.value - delta; + ctrl.value = ctrl.clamp(ctrl.from, v, ctrl.to); + } + } +} |
