summaryrefslogtreecommitdiffstats
path: root/src/widget/knobeventhandler.h
blob: f06fbc26cece76c4e1a2cbc8f38098a9015a9879 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#pragma once

#include <QMouseEvent>
#include <QWheelEvent>
#include <QColor>
#include <QCursor>
#include <QApplication>
#include <QPoint>
#include <QPixmap>

#include "util/math.h"

template <class T>
class KnobEventHandler {
  public:
    KnobEventHandler()
            : m_bRightButtonPressed(false) {
            QPixmap blankPixmap(32, 32);
            blankPixmap.fill(QColor(0, 0, 0, 0));
            m_blankCursor = QCursor(blankPixmap);
    }

    double valueFromMouseEvent(T* pWidget, QMouseEvent* e) {
        QPoint cur(e->globalPos());
        QPoint diff(cur - m_startPos);
        double dist = sqrt(static_cast<double>(diff.x() * diff.x() + diff.y() * diff.y()));
        bool y_dominant = abs(diff.y()) > abs(diff.x());

        // if y is dominant, then thread an increase in dy as negative (y is
        // pointed downward). Otherwise, if y is not dominant and x has
        // decreased, then thread it as negative.
        if ((y_dominant && diff.y() > 0) || (!y_dominant && diff.x() < 0)) {
            dist = -dist;
        }

        // For legacy (MIDI) reasons this is tuned to 127.
        double value = pWidget->getControlParameter() + dist / 127.0;

        // Clamp to [0.0, 1.0]
        value = math_clamp(value, 0.0, 1.0);

        return value;
    }

    void mouseMoveEvent(T* pWidget, QMouseEvent* e) {
        if (!m_bRightButtonPressed) {
            QCursor::setPos(m_startPos);
            double value = valueFromMouseEvent(pWidget, e);
            pWidget->setControlParameterDown(value);
            pWidget->inputActivity();
        }
    }

    void mousePressEvent(T* pWidget, QMouseEvent* e) {
        switch (e->button()) {
            case Qt::RightButton:
                pWidget->resetControlParameter();
                m_bRightButtonPressed = true;
                break;
            case Qt::LeftButton:
            case Qt::MiddleButton:
                m_startPos = e->globalPos();
                // Somehow using Qt::BlankCursor does not work on Windows
                // https://mixxx.org/forums/viewtopic.php?p=40298#p40298
                QApplication::setOverrideCursor(m_blankCursor);
                break;
            default:
                break;
        }
    }

    void mouseReleaseEvent(T* pWidget, QMouseEvent* e) {
        double value = 0.0;
        switch (e->button()) {
            case Qt::LeftButton:
            case Qt::MiddleButton:
                QCursor::setPos(m_startPos);
                QApplication::restoreOverrideCursor();
                value = valueFromMouseEvent(pWidget, e);
                pWidget->setControlParameterUp(value);
                pWidget->inputActivity();
                break;
            case Qt::RightButton:
                m_bRightButtonPressed = false;
                break;
            default:
                break;
        }
    }

    void wheelEvent(T* pWidget, QWheelEvent* e) {
        // For legacy (MIDI) reasons this is tuned to 127.
        double wheelDirection = e->angleDelta().y() / (120.0 * 127.0);
        double newValue = pWidget->getControlParameter() + wheelDirection;

        // Clamp to [0.0, 1.0]
        newValue = math_clamp(newValue, 0.0, 1.0);

        pWidget->setControlParameter(newValue);
        pWidget->inputActivity();
        e->accept();
    }

  private:
    // True if right mouse button is pressed.
    bool m_bRightButtonPressed;

    // Starting point when left mouse button is pressed
    QPoint m_startPos;
    QCursor m_blankCursor;
};