• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 28737374357

05 Jul 2026 10:14AM UTC coverage: 35.285% (-0.002%) from 35.287%
28737374357

push

github

mcallegari
qmlui: improve VCXYPad feedback and relative movements

18560 of 52600 relevant lines covered (35.29%)

40987.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.41
/engine/src/qlcinputsource.cpp
1
/*
2
  Q Light Controller
3
  qlcinputsource.cpp
4

5
  Copyright (C) Heikki Junnila
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QMutexLocker>
21
#include <QDebug>
22

23
#if defined(WIN32) || defined (Q_OS_WIN)
24
 #include <Windows.h>
25
#endif
26

27
#include "qlcinputsource.h"
28
#include "qlcmacros.h"
29

30
quint32 QLCInputSource::invalidUniverse = UINT_MAX;
31
quint32 QLCInputSource::invalidChannel = UINT_MAX;
32
quint32 QLCInputSource::invalidID = UINT_MAX;
33

34
QLCInputSource::QLCInputSource(QThread *parent)
2✔
35
    : QThread(parent)
36
    , m_universe(invalidUniverse)
2✔
37
    , m_channel(invalidChannel)
2✔
38
    , m_id(invalidID)
2✔
39
    , m_workingMode(Absolute)
2✔
40
    , m_sensitivity(20)
2✔
41
    , m_emitExtraPressRelease(false)
2✔
42
    , m_inputValue(0)
2✔
43
    , m_outputValue(0)
2✔
44
    , m_running(false)
2✔
45
{
46
    m_lower.setType(QLCInputFeedback::LowerValue);
2✔
47
    m_lower.setValue(0);
2✔
48
    m_upper.setType(QLCInputFeedback::UpperValue);
2✔
49
    m_upper.setValue(UCHAR_MAX);
2✔
50
    m_monitor.setType(QLCInputFeedback::MonitorValue);
2✔
51
    m_monitor.setValue(UCHAR_MAX);
2✔
52
}
2✔
53

54
QLCInputSource::QLCInputSource(quint32 universe, quint32 channel, QThread *parent)
46✔
55
    : QThread(parent)
56
    , m_universe(universe)
46✔
57
    , m_channel(channel)
46✔
58
    , m_workingMode(Absolute)
46✔
59
    , m_sensitivity(20)
46✔
60
    , m_emitExtraPressRelease(false)
46✔
61
    , m_inputValue(0)
46✔
62
    , m_outputValue(0)
46✔
63
    , m_running(false)
46✔
64
{
65
    m_lower.setType(QLCInputFeedback::LowerValue);
46✔
66
    m_lower.setValue(0);
46✔
67
    m_upper.setType(QLCInputFeedback::UpperValue);
46✔
68
    m_upper.setValue(UCHAR_MAX);
46✔
69
    m_monitor.setType(QLCInputFeedback::MonitorValue);
46✔
70
    m_monitor.setValue(UCHAR_MAX);
46✔
71
}
46✔
72

73
QLCInputSource::~QLCInputSource()
72✔
74
{
75
    if (m_running == true)
36✔
76
    {
77
        m_running = false;
×
78
        wait();
×
79
    }
80
}
72✔
81

82
bool QLCInputSource::isValid() const
143✔
83
{
84
    if (universe() != invalidUniverse && channel() != invalidChannel)
143✔
85
        return true;
139✔
86
    else
87
        return false;
4✔
88
}
89

90
void QLCInputSource::setUniverse(quint32 uni)
×
91
{
92
    m_universe = uni;
×
93
}
×
94

95
quint32 QLCInputSource::universe() const
277✔
96
{
97
    return m_universe;
277✔
98
}
99

100
void QLCInputSource::setChannel(quint32 ch)
×
101
{
102
    m_channel = ch;
×
103
}
×
104

105
quint32 QLCInputSource::channel() const
217✔
106
{
107
    return m_channel;
217✔
108
}
109

110
void QLCInputSource::setPage(ushort pgNum)
×
111
{
112
    quint32 chCopy = m_channel & 0x0000FFFF;
×
113
    m_channel = ((quint32)pgNum << 16) | chCopy;
×
114
}
×
115

116
ushort QLCInputSource::page() const
4✔
117
{
118
    return (ushort)(m_channel >> 16);
4✔
119
}
120

121
void QLCInputSource::setID(quint32 id)
×
122
{
123
    m_id = id;
×
124
}
×
125

126
quint32 QLCInputSource::id() const
×
127
{
128
    return m_id;
×
129
}
130

131
/*********************************************************************
132
 * Custom feedback
133
 *********************************************************************/
134

135
uchar QLCInputSource::feedbackValue(QLCInputFeedback::FeedbackType type) const
56✔
136
{
137
    switch (type)
56✔
138
    {
139
        case QLCInputFeedback::LowerValue: return m_lower.value();
20✔
140
        case QLCInputFeedback::UpperValue: return m_upper.value();
21✔
141
        case QLCInputFeedback::MonitorValue: return m_monitor.value();
15✔
142
        default: return 0;
×
143
    }
144
}
145

146
void QLCInputSource::setFeedbackValue(QLCInputFeedback::FeedbackType type, uchar value)
30✔
147
{
148
    switch (type)
30✔
149
    {
150
        case QLCInputFeedback::LowerValue:
10✔
151
            m_lower.setValue(value);
10✔
152
        break;
10✔
153
        case QLCInputFeedback::UpperValue:
10✔
154
            m_upper.setValue(value);
10✔
155
        break;
10✔
156
        case QLCInputFeedback::MonitorValue:
10✔
157
            m_monitor.setValue(value);
10✔
158
        break;
10✔
159
        default:
×
160
        break;
×
161
    }
162
}
30✔
163

164
QVariant QLCInputSource::feedbackExtraParams(QLCInputFeedback::FeedbackType type) const
59✔
165
{
166
    switch (type)
59✔
167
    {
168
        case QLCInputFeedback::LowerValue: return m_lower.extraParams();
20✔
169
        case QLCInputFeedback::UpperValue: return m_upper.extraParams();
24✔
170
        case QLCInputFeedback::MonitorValue: return m_monitor.extraParams();
15✔
171
        default: return 0;
×
172
    }
173
}
174

175
void QLCInputSource::setFeedbackExtraParams(QLCInputFeedback::FeedbackType type, QVariant params)
9✔
176
{
177
    switch (type)
9✔
178
    {
179
        case QLCInputFeedback::LowerValue:
3✔
180
            m_lower.setExtraParams(params);
3✔
181
        break;
3✔
182
        case QLCInputFeedback::UpperValue:
3✔
183
            m_upper.setExtraParams(params);
3✔
184
        break;
3✔
185
        case QLCInputFeedback::MonitorValue:
3✔
186
            m_monitor.setExtraParams(params);
3✔
187
        break;
3✔
188
        default:
×
189
        break;
×
190
    }
191
}
9✔
192

193
/*********************************************************************
194
 * Working mode
195
 *********************************************************************/
196

197
QLCInputSource::WorkingMode QLCInputSource::workingMode() const
×
198
{
199
    return m_workingMode;
×
200
}
201

202
void QLCInputSource::setWorkingMode(QLCInputSource::WorkingMode mode)
×
203
{
204
    m_workingMode = mode;
×
205

206
    if (m_workingMode == Relative && m_running == false)
×
207
    {
208
        m_inputValue = 127;
×
209
        m_running = true;
×
210
        start();
×
211
    }
212
    else if ((m_workingMode == Absolute || m_workingMode == Encoder) && m_running == true)
×
213
    {
214
        m_running = false;
×
215
        if (m_workingMode == Encoder)
×
216
            m_sensitivity = 1;
×
217
        wait();
×
218
        qDebug() << Q_FUNC_INFO << "Thread stopped for universe" << m_universe << "channel" << m_channel;
×
219
    }
220
}
×
221

222
bool QLCInputSource::needsUpdate() const
37✔
223
{
224
    if (m_workingMode == Relative || m_workingMode == Encoder ||
37✔
225
        m_emitExtraPressRelease == true)
37✔
226
            return true;
×
227

228
    return false;
37✔
229
}
230

231
int QLCInputSource::sensitivity() const
×
232
{
233
    return m_sensitivity;
×
234
}
235

236
void QLCInputSource::setSensitivity(int value)
×
237
{
238
    m_sensitivity = value;
×
239
}
×
240

241
bool QLCInputSource::sendExtraPressRelease() const
×
242
{
243
    return m_emitExtraPressRelease;
×
244
}
245

246
void QLCInputSource::setSendExtraPressRelease(bool enable)
×
247
{
248
    m_emitExtraPressRelease = enable;
×
249
}
×
250

251
void QLCInputSource::updateInputValue(uchar value)
×
252
{
253
    QMutexLocker locker(&m_mutex);
×
254
    if (m_workingMode == Encoder)
×
255
    {
256
        // Detect the rotation direction by comparing the raw value with the
257
        // previous one received from the controller...
258
        if (value < m_inputValue)
×
259
            m_sensitivity = -qAbs(m_sensitivity);
×
260
        else if (value > m_inputValue)
×
261
            m_sensitivity = qAbs(m_sensitivity);
×
262
        m_inputValue = value;
×
263

264
        // ...then step the actual item value (kept in sync via feedback) by
265
        // the sensitivity, so the encoder acts relative to the current position
266
        m_outputValue = CLAMP(m_outputValue + (char)m_sensitivity, 0, UCHAR_MAX);
×
267
        uchar newValue = m_outputValue;
×
268
        locker.unlock();
×
269
        emit inputValueChanged(m_universe, m_channel, newValue);
×
270
    }
271
    else if (m_emitExtraPressRelease == true)
×
272
    {
273
        locker.unlock();
×
274
        emit inputValueChanged(m_universe, m_channel, m_upper.value());
×
275
        emit inputValueChanged(m_universe, m_channel, m_lower.value());
×
276
    }
277
    else
278
        m_inputValue = value;
×
279
}
×
280

281
void QLCInputSource::updateOuputValue(uchar value)
×
282
{
283
    QMutexLocker locker(&m_mutex);
×
284
    m_outputValue = value;
×
285
}
×
286

287
void QLCInputSource::run()
×
288
{
289
    qDebug() << Q_FUNC_INFO << "Thread started for universe" << m_universe << "channel" << m_channel;
×
290

291
    uchar inputValueCopy = m_inputValue;
×
292
    double dValue = m_outputValue;
×
293
    uchar lastOutputValue = m_outputValue;
×
294
    bool movementOn = false;
×
295

296
    while (m_running == true)
×
297
    {
298
        msleep(50);
×
299

300
        QMutexLocker locker(&m_mutex);
×
301

302
        if (lastOutputValue != m_outputValue)
×
303
            dValue = m_outputValue;
×
304

305
        if (inputValueCopy != m_inputValue || movementOn == true)
×
306
        {
307
            movementOn = false;
×
308
            inputValueCopy = m_inputValue;
×
309
            double moveAmount = 127 - inputValueCopy;
×
310
            if (moveAmount != 0)
×
311
            {
312
                dValue -= (moveAmount / m_sensitivity);
×
313
                dValue = CLAMP(dValue, 0, 255);
×
314

315
                uchar newDmxValue = uchar(dValue);
×
316
                qDebug() << "double value:" << dValue << "uchar val:" << newDmxValue;
×
317
                if (newDmxValue != m_outputValue)
×
318
                    emit inputValueChanged(m_universe, m_channel, newDmxValue);
×
319

320
                movementOn = true;
×
321
            }
322
            lastOutputValue = m_outputValue;
×
323
        }
324
    }
×
325
}
×
326

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc