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

mcallegari / qlcplus / 22831302206

08 Mar 2026 10:26PM UTC coverage: 33.973% (+0.002%) from 33.971%
22831302206

Pull #1974

github

web-flow
Merge 4cabf63f2 into b399c6226
Pull Request #1974: more code improvements

114 of 237 new or added lines in 63 files covered. (48.1%)

1 existing line in 1 file now uncovered.

17651 of 51956 relevant lines covered (33.97%)

19779.77 hits per line

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

0.0
/ui/src/virtualconsole/vcaudiotriggersproperties.cpp
1
/*
2
  Q Light Controller Plus
3
  audiotriggersconfiguration.cpp
4

5
  Copyright (c) Massimo Callegari
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 <QTreeWidgetItem>
21
#include <QToolButton>
22
#include <QComboBox>
23
#include <QSpinBox>
24
#include <qmath.h>
25

26
#include "vcaudiotriggersproperties.h"
27
#include "inputselectionwidget.h"
28
#include "channelsselection.h"
29
#include "functionselection.h"
30
#include "vcwidgetselection.h"
31
#include "vcaudiotriggers.h"
32
#include "audiocapture.h"
33
#include "qlcmacros.h"
34
#include "audiobar.h"
35

36
#define KColumnName             0
37
#define KColumnType             1
38
#define KColumnAssign           2
39
#define KColumnInfo             3
40
#define KColumnMinThreshold     4
41
#define KColumnMaxThreshold     5
42
#define KColumnDivisor          6
43

44
AudioTriggersConfiguration::AudioTriggersConfiguration(VCAudioTriggers *triggers, Doc *doc,
×
45
                                                       int bandsNumber, int maxFrequency)
×
46
    : QDialog(triggers)
47
    , m_doc(doc)
×
48
    , m_maxFrequency(maxFrequency)
×
49
{
50
    setupUi(this);
×
51

52
    m_triggers = triggers;
×
53

54
    m_nameEdit->setText(m_triggers->caption());
×
55

56
    m_barsNumSpin->setFixedWidth(70);
×
57
    m_barsNumSpin->setFixedHeight(30);
×
58
    m_barsNumSpin->setValue(bandsNumber);
×
59

60
    connect(m_barsNumSpin, SIGNAL(valueChanged(int)),
×
61
            this, SLOT(updateTree()));
62

63
    /* External input */
64
    m_inputSelWidget = new InputSelectionWidget(m_doc, this);
×
65
    m_inputSelWidget->setCustomFeedbackVisibility(true);
×
66
    m_inputSelWidget->setKeySequence(m_triggers->keySequence());
×
67
    m_inputSelWidget->setInputSource(m_triggers->inputSource());
×
68
    m_inputSelWidget->setWidgetPage(m_triggers->page());
×
69
    m_inputSelWidget->show();
×
70
    m_extControlLayout->addWidget(m_inputSelWidget);
×
71

72
    m_tree->setAlternatingRowColors(true);
×
73
    m_tree->setRootIsDecorated(false);
×
74
    m_tree->setSelectionMode(QAbstractItemView::NoSelection);
×
75
    m_tree->setAllColumnsShowFocus(true);
×
76

77
    updateTree();
×
78
}
×
79

80
AudioTriggersConfiguration::~AudioTriggersConfiguration()
×
81
{
82
}
×
83

84
void AudioTriggersConfiguration::accept()
×
85
{
86
    m_triggers->setCaption(m_nameEdit->text());
×
87
    m_triggers->setKeySequence(m_inputSelWidget->keySequence());
×
88
    m_triggers->setInputSource(m_inputSelWidget->inputSource());
×
89

90
    /* Close dialog */
91
    QDialog::accept();
×
92
}
×
93

94
void AudioTriggersConfiguration::updateTreeItem(QTreeWidgetItem *item, int idx)
×
95
{
96
    if (item == NULL)
×
97
        return;
×
98

99
    AudioBar *bar = m_triggers->getSpectrumBar(idx);
×
100
    bar->setName(item->text(KColumnName));
×
101

102
    bar->debugInfo();
×
103
    QComboBox *currCombo = (QComboBox *)m_tree->itemWidget(item, KColumnType);
×
104
    if (currCombo != NULL)
×
105
    {
106
        disconnect(currCombo, SIGNAL(currentIndexChanged(int)),
×
107
                   this, SLOT(slotTypeComboChanged(int)));
108
        m_tree->removeItemWidget(item, KColumnType);
×
109
    }
110
    m_tree->removeItemWidget(item, KColumnAssign);
×
111
    m_tree->removeItemWidget(item, KColumnMinThreshold);
×
112
    m_tree->removeItemWidget(item, KColumnMaxThreshold);
×
113
    m_tree->removeItemWidget(item, KColumnDivisor);
×
114

115
    QComboBox *combo = new QComboBox();
×
116
    combo->addItem(QIcon(":/uncheck.png"), tr("None"), idx);
×
117
    combo->addItem(QIcon(":/intensity.png"), tr("DMX"), idx);
×
118
    combo->addItem(QIcon(":/function.png"), tr("Function"), idx);
×
119
    combo->addItem(QIcon(":/virtualconsole.png"), tr("VC Widget"), idx);
×
120
    combo->setCurrentIndex(bar->m_type);
×
121
    m_tree->setItemWidget(item, KColumnType, combo);
×
122
    connect(combo, SIGNAL(currentIndexChanged(int)),
×
123
            this, SLOT(slotTypeComboChanged(int)));
124

NEW
125
    if (bar->m_type == AudioBar::BarType::DMXBar)
×
126
    {
127
        QToolButton *btn = new QToolButton();
×
128
        btn->setIcon(QIcon(":/attach.png"));
×
129
        btn->setProperty("index", idx);
×
130
        m_tree->setItemWidget(item, KColumnAssign, btn);
×
131
        connect(btn, SIGNAL(clicked()), this, SLOT(slotDmxSelectionClicked()));
×
132
        item->setText(KColumnInfo, tr("%1 channels").arg(bar->m_dmxChannels.count()));
×
133
    }
NEW
134
    else if (bar->m_type == AudioBar::BarType::FunctionBar)
×
135
    {
136
        QToolButton *btn = new QToolButton();
×
137
        btn->setIcon(QIcon(":/attach.png"));
×
138
        btn->setProperty("index", idx);
×
139
        m_tree->setItemWidget(item, KColumnAssign, btn);
×
140
        connect(btn, SIGNAL(clicked()), this, SLOT(slotFunctionSelectionClicked()));
×
141
        if (bar->m_function != NULL)
×
142
        {
143
            item->setText(KColumnInfo, bar->m_function->name());
×
144
            item->setIcon(KColumnInfo, bar->m_function->getIcon());
×
145
        }
146
        else
147
        {
148
            item->setText(KColumnInfo, tr("No function"));
×
149
            item->setIcon(KColumnInfo, QIcon());
×
150
        }
151
    }
NEW
152
    else if (bar->m_type == AudioBar::BarType::VCWidgetBar)
×
153
    {
154
        QToolButton *btn = new QToolButton();
×
155
        btn->setIcon(QIcon(":/attach.png"));
×
156
        btn->setProperty("index", idx);
×
157
        m_tree->setItemWidget(item, KColumnAssign, btn);
×
158
        connect(btn, SIGNAL(clicked()), this, SLOT(slotWidgetSelectionClicked()));
×
159
        if (bar->widget() != NULL)
×
160
        {
161
            item->setText(KColumnInfo, bar->widget()->caption());
×
162
            item->setIcon(KColumnInfo, VCWidget::typeToIcon(bar->widget()->type()));
×
163
        }
164
        else
165
        {
166
            item->setText(KColumnInfo, tr("No widget"));
×
167
            item->setIcon(KColumnInfo, QIcon());
×
168
        }
169
    }
170
    else
171
    {
172
        item->setText(KColumnInfo, tr("Not assigned"));
×
173
        item->setIcon(KColumnInfo, QIcon());
×
174
    }
175

NEW
176
    if (bar->m_type == AudioBar::BarType::FunctionBar
×
NEW
177
        || (bar->m_type == AudioBar::BarType::VCWidgetBar && ((bar->widget() == NULL) || bar->widget()->type() != VCWidget::SliderWidget)))
×
178
    {
179
        QSpinBox *minspin = new QSpinBox();
×
180
        minspin->setMinimum(5);
×
181
        minspin->setMaximum(95);
×
182
        minspin->setSingleStep(1);
×
183
        minspin->setSuffix("%");
×
184
        minspin->setValue(SCALE(float(bar->m_minThreshold), 0.0, 255.0, 0.0, 100.0));
×
185
        minspin->setProperty("index", idx);
×
186
        connect(minspin, SIGNAL(valueChanged(int)), this, SLOT(slotMinThresholdChanged(int)));
×
187
        m_tree->setItemWidget(item, KColumnMinThreshold, minspin);
×
188

189
        QSpinBox *maxspin = new QSpinBox();
×
190
        maxspin->setMinimum(5);
×
191
        maxspin->setMaximum(95);
×
192
        maxspin->setSingleStep(1);
×
193
        maxspin->setSuffix("%");
×
194
        maxspin->setValue(SCALE(float(bar->m_maxThreshold), 0.0, 255.0, 0.0, 100.0));
×
195
        maxspin->setProperty("index", idx);
×
196
        connect(maxspin, SIGNAL(valueChanged(int)), this, SLOT(slotMaxThresholdChanged(int)));
×
197
        m_tree->setItemWidget(item, KColumnMaxThreshold, maxspin);
×
198
    }
199

NEW
200
    if (bar->m_type == AudioBar::BarType::VCWidgetBar
×
201
        && bar->widget() != NULL
×
202
        && (bar->widget()->type() == VCWidget::SpeedDialWidget || bar->widget()->type() == VCWidget::CueListWidget))
×
203
    {
204
        QSpinBox *divisor = new QSpinBox();
×
205
        divisor->setMinimum(1);
×
206
        divisor->setMaximum(64);
×
207
        divisor->setSingleStep(1);
×
208
        divisor->setValue(bar->m_divisor);
×
209
        divisor->setProperty("index", idx);
×
210
        connect(divisor, SIGNAL(valueChanged(int)), this, SLOT(slotDivisorChanged(int)));
×
211
        m_tree->setItemWidget(item, KColumnDivisor, divisor);
×
212
    }
213
}
214

215
void AudioTriggersConfiguration::updateTree()
×
216
{
217
    if (m_barsNumSpin->value() < m_barsNumSpin->minimum() ||
×
218
        m_barsNumSpin->value() > m_barsNumSpin->maximum())
×
219
            return;
×
220

221
    m_tree->clear();
×
222
    m_triggers->setSpectrumBarsNumber(m_barsNumSpin->value());
×
223

224
    // add volume item
225
    QTreeWidgetItem *volItem = new QTreeWidgetItem(m_tree);
×
226
    volItem->setText(KColumnName, tr("Volume Bar"));
×
227
    updateTreeItem(volItem, 1000);
×
228

229
    const int bandsNumber = m_barsNumSpin->value();
×
230
    const double minFreq = AudioCapture::minFrequency();
×
231
    const double maxFreq = m_maxFrequency;
×
232
    const double logRange = (bandsNumber > 0 && maxFreq > minFreq) ? qLn(maxFreq / minFreq) : 0.0;
×
233

234
    for (int i = 0; i < bandsNumber; i++)
×
235
    {
236
        double bandStartFreq = minFreq;
×
237
        double bandEndFreq = maxFreq;
×
238
        if (logRange > 0.0)
×
239
        {
240
            bandStartFreq = minFreq * qExp(logRange * (double(i) / double(bandsNumber)));
×
241
            bandEndFreq = minFreq * qExp(logRange * (double(i + 1) / double(bandsNumber)));
×
242
        }
243

244
        int bandStartHz = qCeil(bandStartFreq);
×
245
        int bandEndHz = (i == bandsNumber - 1) ? int(maxFreq) : (qCeil(bandEndFreq) - 1);
×
246
        if (bandEndHz <= bandStartHz)
×
247
            bandEndHz = bandStartHz;
×
248

249
        QTreeWidgetItem *barItem = new QTreeWidgetItem(m_tree);
×
250
        barItem->setText(KColumnName, tr("#%1 (%2Hz - %3Hz)").arg(i + 1).arg(bandStartHz).arg(bandEndHz));
×
251
        updateTreeItem(barItem, i);
×
252
    }
253

254
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
255
}
256

257
void AudioTriggersConfiguration::slotTypeComboChanged(int comboIndex)
×
258
{
259
    QComboBox *combo = (QComboBox *)sender();
×
260
    int index = combo->itemData(comboIndex).toInt();
×
261
    QTreeWidgetItem *item = NULL;
×
262
    if (index == 1000)
×
263
        item = m_tree->topLevelItem(0);
×
264
    else
265
        item = m_tree->topLevelItem(index + 1);
×
266

267
    m_triggers->setSpectrumBarType(index, comboIndex);
×
268

269
    updateTreeItem(item, index);
×
270
}
×
271

272
void AudioTriggersConfiguration::slotDmxSelectionClicked()
×
273
{
274
    QToolButton *btn = (QToolButton *)sender();
×
275
    QVariant prop = btn->property("index");
×
276
    if (prop.isValid())
×
277
    {
278
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
279
        ChannelsSelection cfg(m_doc, this);
×
280
        if (bar != NULL)
×
281
            cfg.setChannelsList(bar->m_dmxChannels);
×
282
        if (cfg.exec() == QDialog::Rejected)
×
283
            return; // User pressed cancel
×
284

285
        QList<SceneValue> dmxList = cfg.channelsList();
×
286
        if (bar != NULL)
×
287
            bar->attachDmxChannels(m_doc, dmxList);
×
288
        QTreeWidgetItem *item = NULL;
×
289
        if (prop.toInt() == 1000)
×
290
            item = m_tree->topLevelItem(0);
×
291
        else
292
            item = m_tree->topLevelItem(prop.toInt() + 1);
×
293
        updateTreeItem(item, prop.toInt());
×
294
    }
×
295
}
×
296

297
void AudioTriggersConfiguration::slotFunctionSelectionClicked()
×
298
{
299
    QToolButton *btn = (QToolButton *)sender();
×
300
    QVariant prop = btn->property("index");
×
301
    if (prop.isValid())
×
302
    {
303
        FunctionSelection fs(this, m_doc);
×
304
        fs.setMultiSelection(false);
×
305
        if (fs.exec() == QDialog::Rejected || fs.selection().size() == 0)
×
306
            return; // User pressed cancel or made an invalid selection
×
307
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
308
        Function *f = m_doc->function(fs.selection().first());
×
309
        if (bar != NULL && f != NULL)
×
310
            bar->attachFunction(f);
×
311

312
        QTreeWidgetItem *item = NULL;
×
313
        if (prop.toInt() == 1000)
×
314
            item = m_tree->topLevelItem(0);
×
315
        else
316
            item = m_tree->topLevelItem(prop.toInt() + 1);
×
317
        updateTreeItem(item, prop.toInt());
×
318
    }
×
319
}
×
320

321
void AudioTriggersConfiguration::slotWidgetSelectionClicked()
×
322
{
323
    QToolButton *btn = (QToolButton *)sender();
×
324
    QVariant prop = btn->property("index");
×
325
    if (prop.isValid())
×
326
    {
327
        QList<int> filters;
×
328
        filters.append(VCWidget::SliderWidget);
×
329
        filters.append(VCWidget::ButtonWidget);
×
330
        filters.append(VCWidget::SpeedDialWidget);
×
331
        filters.append(VCWidget::CueListWidget);
×
332
        VCWidgetSelection ws(filters, this);
×
333
        if (ws.exec() == QDialog::Rejected || ws.getSelectedWidget() == 0)
×
334
            return; // User pressed cancel or did not select any widget
×
335
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
336
        if (bar != NULL)
×
337
        {
338
            bar->attachWidget(ws.getSelectedWidget()->id());
×
339
        }
340

341
        QTreeWidgetItem *item = NULL;
×
342
        if (prop.toInt() == 1000)
×
343
            item = m_tree->topLevelItem(0);
×
344
        else
345
            item = m_tree->topLevelItem(prop.toInt() + 1);
×
346
        updateTreeItem(item, prop.toInt());
×
347
    }
×
348
}
×
349

350
void AudioTriggersConfiguration::slotMinThresholdChanged(int val)
×
351
{
352
    QSpinBox *spin = (QSpinBox *)sender();
×
353
    QVariant prop = spin->property("index");
×
354
    if (prop.isValid())
×
355
    {
356
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
357
        uchar scaledVal = SCALE(float(val), 0.0, 100.0, 0.0, 255.0);
×
358
        if (bar != NULL)
×
359
            bar->setMinThreshold(scaledVal);
×
360
    }
361
}
×
362

363
void AudioTriggersConfiguration::slotMaxThresholdChanged(int val)
×
364
{
365
    QSpinBox *spin = (QSpinBox *)sender();
×
366
    QVariant prop = spin->property("index");
×
367
    if (prop.isValid())
×
368
    {
369
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
370
        uchar scaledVal = SCALE(float(val), 0.0, 100.0, 0.0, 255.0);
×
371
        if (bar != NULL)
×
372
            bar->setMaxThreshold(scaledVal);
×
373
    }
374
}
×
375

376
void AudioTriggersConfiguration::slotDivisorChanged(int val)
×
377
{
378
    QSpinBox *spin = (QSpinBox *)sender();
×
379
    QVariant prop = spin->property("index");
×
380
    if (prop.isValid())
×
381
    {
382
        AudioBar *bar = m_triggers->getSpectrumBar(prop.toInt());
×
383
        if (bar != NULL)
×
384
            bar->setDivisor(val);
×
385
    }
386
}
×
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