summaryrefslogtreecommitdiffstats
path: root/src/waveform/renderers/waveformsignalcolors.cpp
blob: 41bbf22b6ae6ccecb4f059bb2cb903514e47d1de (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "waveformsignalcolors.h"

#include <QDomNode>

#include "widget/wskincolor.h"
#include "widget/wwidget.h"

WaveformSignalColors::WaveformSignalColors() {
}

bool WaveformSignalColors::setup(const QDomNode &node, const SkinContext& context) {
    // NOTE(rryan): It is critical that every color is converted to RGB with
    // toRgb(). Otherwise Mixxx will waste 3% of its CPU time while rendering
    // the filtered waveform doing RGB color space conversions!

    m_signalColor.setNamedColor(context.selectString(node, "SignalColor"));
    m_signalColor = WSkinColor::getCorrectColor(m_signalColor).toRgb();

    m_lowColor.setNamedColor(context.selectString(node, "SignalLowColor"));
    m_lowColor = WSkinColor::getCorrectColor(m_lowColor).toRgb();

    m_midColor.setNamedColor(context.selectString(node, "SignalMidColor"));
    m_midColor = WSkinColor::getCorrectColor(m_midColor).toRgb();

    m_highColor.setNamedColor(context.selectString(node, "SignalHighColor"));
    m_highColor = WSkinColor::getCorrectColor(m_highColor).toRgb();

    m_rgbLowColor.setNamedColor(context.selectString(node, "SignalRGBLowColor"));
    if (!m_rgbLowColor.isValid()) {
        m_rgbLowColor = Qt::red;
    }
    m_rgbLowColor = WSkinColor::getCorrectColor(m_rgbLowColor).toRgb();

    m_rgbMidColor.setNamedColor(context.selectString(node, "SignalRGBMidColor"));
    if (!m_rgbMidColor.isValid()) {
        m_rgbMidColor = Qt::green;
    }
    m_rgbMidColor = WSkinColor::getCorrectColor(m_rgbMidColor).toRgb();

    m_rgbHighColor.setNamedColor(context.selectString(node, "SignalRGBHighColor"));
    if (!m_rgbHighColor.isValid()) {
        m_rgbHighColor = Qt::blue;
    }
    m_rgbHighColor = WSkinColor::getCorrectColor(m_rgbHighColor).toRgb();

    m_axesColor = context.selectColor(node, "AxesColor");
    if (!m_axesColor.isValid()) {
        m_axesColor = QColor(245,245,245);
    }
    m_axesColor = WSkinColor::getCorrectColor(m_axesColor).toRgb();

    m_playPosColor = context.selectColor(node, "PlayPosColor");
    m_playPosColor = WSkinColor::getCorrectColor(m_playPosColor).toRgb();
    if (!m_playPosColor.isValid()) {
        m_playPosColor = m_axesColor;
    }

    // This color is used to draw an overlay over the played part the overview-waveforms
    m_playedOverlayColor = context.selectColor(node, "PlayedOverlayColor");
    m_playedOverlayColor = WSkinColor::getCorrectColor(m_playedOverlayColor).toRgb();
    if (!m_playedOverlayColor.isValid()) {
        m_playedOverlayColor = Qt::transparent;
    }

    // This color is used to draw an overlay over the entire overview-waveforms
    // if vinyl passthrough is enabled
    m_passthroughOverlayColor = context.selectColor(node, "PassthroughOverlayColor");
    m_passthroughOverlayColor = WSkinColor::getCorrectColor(m_passthroughOverlayColor).toRgb();
    if (!m_passthroughOverlayColor.isValid()) {
        m_passthroughOverlayColor = WSkinColor::getCorrectColor(QColor(187, 0, 0, 0)).toRgb();
    }

    m_bgColor = context.selectColor(node, "BgColor");
    if (!m_bgColor.isValid()) {
        m_bgColor = Qt::transparent;
    }
    m_bgColor = WSkinColor::getCorrectColor(m_bgColor).toRgb();

    bool filteredColorValid = m_lowColor.isValid() && m_midColor.isValid() && m_highColor.isValid();

    if (m_signalColor.isValid() && filteredColorValid) {
        return true; //default
    }

    if (m_signalColor.isValid() && !filteredColorValid) {
        fallBackFromSignalColor(); //pre waveform-2.0 skins
        return false;
    }

    fallBackDefaultColor();
    return false;
}

void WaveformSignalColors::fallBackFromSignalColor() {
    // qWarning() << "WaveformSignalColors::fallBackFromSignalColor - "
    //           << "skin do not provide low/mid/high signal colors";

    // NOTE(rryan): On ARM, qreal is float so it's important we use qreal here
    // and not double or float or else we will get build failures on ARM.
    qreal h, s, l, a;
    m_signalColor.getHslF(&h,&s,&l,&a);

    const double analogousAngle = 1.0/12.0;

    if (s < 0.1) { // gray
        const qreal sMax = 1.0 - h;
        m_lowColor.setHslF(h,s,l);
        m_midColor.setHslF(h,s+sMax*0.2,l);
        m_highColor.setHslF(h,s+sMax*0.4,l);
    } else {
        if (l < 0.1) { // ~white
            const qreal lMax = 1.0 - l;
            m_lowColor.setHslF(h,s,l);
            m_midColor.setHslF(h,s,l+lMax*0.2);
            m_highColor.setHslF(h,s,l+lMax*0.4);
        } else if (l < 0.5) {
            const qreal lMax = 1.0 - l;
            m_lowColor.setHslF(h,s,l);
            m_midColor.setHslF(stableHue(h-analogousAngle*0.3),s,l+lMax*0.1);
            m_highColor.setHslF(stableHue(h+analogousAngle*0.3),s,l+lMax*0.4);
        } else if (l < 0.9) {
            const qreal lMin = l;
            m_lowColor.setHslF(h,s,l);
            m_midColor.setHslF(stableHue(h-analogousAngle*0.3),s,l-lMin*0.1);
            m_highColor.setHslF(stableHue(h+analogousAngle*0.3),s,l-lMin*0.4);
        } else { // ~black
            const qreal lMin = l;
            m_lowColor.setHslF(h,s,l);
            m_midColor.setHslF(h,s,l-lMin*0.2);
            m_highColor.setHslF(h,s,l-lMin*0.4);
        }
    }


    // NOTE(rryan): It is critical that every color is converted to RGB with
    // toRgb(). Otherwise Mixxx will waste 3% of its CPU time while rendering
    // the filtered waveform doing RGB color space conversions!
    m_lowColor = m_lowColor.toRgb();
    m_midColor = m_midColor.toRgb();
    m_highColor = m_highColor.toRgb();
}

void WaveformSignalColors::fallBackDefaultColor() {
    qWarning() << "WaveformSignalColors::fallBackDefaultColor - " \
                  "skin do not provide valid signal colors ! Default colors is use ...";

    m_signalColor = Qt::green;
    m_signalColor = m_signalColor.toRgb();
    fallBackFromSignalColor();
}

//NOTE(vRince) this sabilise hue between -1.0 and 2.0 but not more !
float WaveformSignalColors::stableHue(float hue) const {
    return hue < 0.0 ? hue + 1.0 : hue > 1.0 ? hue - 1.0 : hue;
}