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

mcallegari / qlcplus / 28530951808

01 Jul 2026 04:03PM UTC coverage: 35.287% (+0.01%) from 35.277%
28530951808

push

github

mcallegari
engine: fix EFX test unit

18560 of 52598 relevant lines covered (35.29%)

40989.4 hits per line

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

0.0
/ui/src/efxeditor.cpp
1
/*
2
  Q Light Controller
3
  efxeditor.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 <QTreeWidgetItem>
21
#include <QTreeWidget>
22
#include <QMessageBox>
23
#include <QPaintEvent>
24
#include <QSettings>
25
#include <QComboBox>
26
#include <QCheckBox>
27
#include <QLineEdit>
28
#include <QCheckBox>
29
#include <QSpinBox>
30
#include <QGridLayout>
31
#include <QPainter>
32
#include <QLabel>
33
#include <QDebug>
34
#include <QPen>
35

36
#include "fixtureselection.h"
37
#include "speeddialwidget.h"
38
#include "efxpreviewarea.h"
39
#include "efxeditor.h"
40
#include "fixture.h"
41
#include "doc.h"
42

43
#define SETTINGS_GEOMETRY "efxeditor/geometry"
44

45
#define KColumnNumber  0
46
#define KColumnName    1
47
#define KColumnMode    2
48
#define KColumnReverse 3
49
#define KColumnStartOffset 4
50

51
#define PROPERTY_FIXTURE "fixture"
52
#define UI_STATE_TAB_INDEX "tabIndex"
53
#define UI_STATE_SHOW_DIAL "showDial"
54

55
#define KTabGeneral 0
56
#define KTabMovement 1
57

58
/*****************************************************************************
59
 * Initialization
60
 *****************************************************************************/
61

62
EFXEditor::EFXEditor(QWidget* parent, EFX* efx, Doc* doc)
×
63
    : QWidget(parent)
64
    , m_doc(doc)
×
65
    , m_efx(efx)
×
66
    , m_previewArea(NULL)
×
67
    , m_points(NULL)
×
68
    , m_speedDials(NULL)
×
69
{
70
    Q_ASSERT(doc != NULL);
×
71
    Q_ASSERT(efx != NULL);
×
72

73
    setupUi(this);
×
74

75
    connect(m_speedDial, SIGNAL(toggled(bool)),
×
76
            this, SLOT(slotSpeedDialToggle(bool)));
77

78
    initGeneralPage();
×
79
    initMovementPage();
×
80

81
    QVariant tabIndex = efx->uiStateValue(UI_STATE_TAB_INDEX);
×
82
    if (tabIndex.isNull())
×
83
        m_tab->setCurrentIndex(0);
×
84
    else
85
        m_tab->setCurrentIndex(tabIndex.toInt());
×
86

87
    /* Tab widget */
88
    connect(m_tab, SIGNAL(currentChanged(int)),
×
89
            this, SLOT(slotTabChanged(int)));
90

91
    // Used for UI parameter changes
92
    m_testTimer.setSingleShot(true);
×
93
    m_testTimer.setInterval(500);
×
94
    connect(&m_testTimer, SIGNAL(timeout()), this, SLOT(slotRestartTest()));
×
95
    connect(m_doc, SIGNAL(modeChanged(Doc::Mode)), this, SLOT(slotModeChanged(Doc::Mode)));
×
96

97
    updateSpeedDials();
×
98

99
    QVariant showDial = efx->uiStateValue(UI_STATE_SHOW_DIAL);
×
100
    if (showDial.isNull() == false && showDial.toBool() == true)
×
101
        m_speedDial->setChecked(true);
×
102

103
    // Set focus to the editor
104
    m_nameEdit->setFocus();
×
105
}
×
106

107
EFXEditor::~EFXEditor()
×
108
{
109
    if (m_testButton->isChecked() == true)
×
110
        m_efx->stopAndWait();
×
111
}
×
112

113
void EFXEditor::stopTest()
×
114
{
115
    if (m_testButton->isChecked() == true)
×
116
        m_testButton->click();
×
117
}
×
118

119
void EFXEditor::slotFunctionManagerActive(bool active)
×
120
{
121
    if (active == true)
×
122
    {
123
        updateSpeedDials();
×
124
    }
125
    else
126
    {
127
        if (m_speedDials != NULL)
×
128
            m_speedDials->deleteLater();
×
129
        m_speedDials = NULL;
×
130
    }
131
}
×
132

133
void EFXEditor::initGeneralPage()
×
134
{
135
    // Doc
136
    connect(m_doc, SIGNAL(fixtureRemoved(quint32)), this, SLOT(slotFixtureRemoved()));
×
137
    connect(m_doc, SIGNAL(fixtureChanged(quint32)), this, SLOT(slotFixtureChanged()));
×
138

139
    /* Set the EFX's name to the name field */
140
    m_nameEdit->setText(m_efx->name());
×
141
    m_nameEdit->setSelection(0, m_nameEdit->text().length());
×
142

143
    /* Put all of the EFX's fixtures to the tree view */
144
    updateFixtureTree();
×
145

146
    /* Set propagation mode */
147
    if (m_efx->propagationMode() == EFX::Serial)
×
148
        m_serialRadio->setChecked(true);
×
149
    else if (m_efx->propagationMode() == EFX::Asymmetric)
×
150
        m_asymmetricRadio->setChecked(true);
×
151
    else
152
        m_parallelRadio->setChecked(true);
×
153

154
    /* Disable test button if we're in operate mode */
155
    if (m_doc->mode() == Doc::Operate)
×
156
        m_testButton->setEnabled(false);
×
157

158
    connect(m_nameEdit, SIGNAL(textEdited(const QString&)),
×
159
            this, SLOT(slotNameEdited(const QString&)));
160

161
    connect(m_tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
×
162
            this, SLOT(slotFixtureItemChanged(QTreeWidgetItem*,int)));
163

164
    connect(m_addFixtureButton, SIGNAL(clicked()),
×
165
            this, SLOT(slotAddFixtureClicked()));
166
    connect(m_removeFixtureButton, SIGNAL(clicked()),
×
167
            this, SLOT(slotRemoveFixtureClicked()));
168

169
    connect(m_raiseFixtureButton, SIGNAL(clicked()),
×
170
            this, SLOT(slotRaiseFixtureClicked()));
171
    connect(m_lowerFixtureButton, SIGNAL(clicked()),
×
172
            this, SLOT(slotLowerFixtureClicked()));
173

174
    connect(m_parallelRadio, SIGNAL(toggled(bool)),
×
175
            this, SLOT(slotParallelRadioToggled(bool)));
176
    connect(m_serialRadio, SIGNAL(toggled(bool)),
×
177
            this, SLOT(slotSerialRadioToggled(bool)));
178
    connect(m_asymmetricRadio, SIGNAL(toggled(bool)),
×
179
            this, SLOT(slotAsymmetricRadioToggled(bool)));
180

181
    // Test slots
182
    connect(m_testButton, SIGNAL(clicked()),
×
183
            this, SLOT(slotTestClicked()));
184
    connect(m_raiseFixtureButton, SIGNAL(clicked()),
×
185
            this, SLOT(slotRestartTest()));
186
    connect(m_lowerFixtureButton, SIGNAL(clicked()),
×
187
            this, SLOT(slotRestartTest()));
188
    connect(m_parallelRadio, SIGNAL(toggled(bool)),
×
189
            this, SLOT(slotRestartTest()));
190
    connect(m_serialRadio, SIGNAL(toggled(bool)),
×
191
            this, SLOT(slotRestartTest()));
192
    connect(m_asymmetricRadio, SIGNAL(toggled(bool)),
×
193
            this, SLOT(slotRestartTest()));
194
}
×
195

196
void EFXEditor::initMovementPage()
×
197
{
198
    new QHBoxLayout(m_previewFrame);
×
199
    m_previewArea = new EFXPreviewArea(m_previewFrame);
×
200
    m_previewFrame->layout()->setContentsMargins(0, 0, 0, 0);
×
201
    m_previewFrame->layout()->addWidget(m_previewArea);
×
202

203
    /* Get supported algorithms and fill the algorithm combo with them */
204
    m_algorithmCombo->addItems(EFX::algorithmList());
×
205

206
    QString algo(EFX::algorithmToString(m_efx->algorithm()));
×
207
    int algoIndex = 0;
×
208
    /* Select the EFX's algorithm from the algorithm combo */
209
    for (int i = 0; i < m_algorithmCombo->count(); i++)
×
210
    {
211
        if (m_algorithmCombo->itemText(i) == algo)
×
212
        {
213
            m_algorithmCombo->setCurrentIndex(i);
×
214
            algoIndex = i;
×
215
            break;
×
216
        }
217
    }
218

219
    /* Causes the EFX function to update the preview point array */
220
    slotAlgorithmSelected(algoIndex);
×
221

222
    /* Get the algorithm parameters */
223
    m_widthSpin->setValue(m_efx->width());
×
224
    m_heightSpin->setValue(m_efx->height());
×
225
    m_xOffsetSpin->setValue(m_efx->xOffset());
×
226
    m_yOffsetSpin->setValue(m_efx->yOffset());
×
227
    m_rotationSpin->setValue(m_efx->rotation());
×
228
    m_startOffsetSpin->setValue(m_efx->startOffset());
×
229
    m_isRelativeCheckbox->setChecked(m_efx->isRelative());
×
230

231
    m_xFrequencySpin->setValue(m_efx->xFrequency());
×
232
    m_yFrequencySpin->setValue(m_efx->yFrequency());
×
233
    m_xPhaseSpin->setValue(m_efx->xPhase());
×
234
    m_yPhaseSpin->setValue(m_efx->yPhase());
×
235

236
    /* Dimmer control. A single checkbox, not in the .ui file: when enabled the
237
       EFX drives each fixture's dimmer from its own tilt (full at maximum tilt,
238
       zero at minimum). Off by default. */
239
    QGridLayout *paramsLayout = qobject_cast<QGridLayout*>(m_parametersGroup->layout());
×
240
    if (paramsLayout != NULL)
×
241
    {
242
        int dimRow = paramsLayout->rowCount();
×
243

244
        m_dimmerControlCheck = new QCheckBox(tr("Enable dimmer control"), m_parametersGroup);
×
245
        m_dimmerControlCheck->setChecked(m_efx->dimmerControlEnabled());
×
246
        paramsLayout->addWidget(m_dimmerControlCheck, dimRow, 0, 1, 2);
×
247

248
        connect(m_dimmerControlCheck, SIGNAL(toggled(bool)),
×
249
                this, SLOT(slotDimmerControlToggled(bool)));
250
    }
251

252
    /* Running order */
253
    switch (m_efx->runOrder())
×
254
    {
255
        default:
×
256
        case Function::Loop:
257
            m_loop->setChecked(true);
×
258
        break;
×
259
        case Function::SingleShot:
×
260
            m_singleShot->setChecked(true);
×
261
        break;
×
262
        case Function::PingPong:
×
263
            m_pingPong->setChecked(true);
×
264
        break;
×
265
    }
266

267
    /* Direction */
268
    switch (m_efx->direction())
×
269
    {
270
        default:
×
271
        case Function::Forward:
272
            m_forward->setChecked(true);
×
273
        break;
×
274
        case Function::Backward:
×
275
            m_backward->setChecked(true);
×
276
        break;
×
277
    }
278

279
    connect(m_loop, SIGNAL(clicked()),
×
280
            this, SLOT(slotLoopClicked()));
281
    connect(m_singleShot, SIGNAL(clicked()),
×
282
            this, SLOT(slotSingleShotClicked()));
283
    connect(m_pingPong, SIGNAL(clicked()),
×
284
            this, SLOT(slotPingPongClicked()));
285

286
    connect(m_forward, SIGNAL(clicked()),
×
287
            this, SLOT(slotForwardClicked()));
288
    connect(m_backward, SIGNAL(clicked()),
×
289
            this, SLOT(slotBackwardClicked()));
290

291
    connect(m_algorithmCombo, SIGNAL(activated(int)),
×
292
            this, SLOT(slotAlgorithmSelected(int)));
293
    connect(m_widthSpin, SIGNAL(valueChanged(int)),
×
294
            this, SLOT(slotWidthSpinChanged(int)));
295
    connect(m_heightSpin, SIGNAL(valueChanged(int)),
×
296
            this, SLOT(slotHeightSpinChanged(int)));
297
    connect(m_xOffsetSpin, SIGNAL(valueChanged(int)),
×
298
            this, SLOT(slotXOffsetSpinChanged(int)));
299
    connect(m_yOffsetSpin, SIGNAL(valueChanged(int)),
×
300
            this, SLOT(slotYOffsetSpinChanged(int)));
301
    connect(m_rotationSpin, SIGNAL(valueChanged(int)),
×
302
            this, SLOT(slotRotationSpinChanged(int)));
303
    connect(m_startOffsetSpin, SIGNAL(valueChanged(int)),
×
304
            this, SLOT(slotStartOffsetSpinChanged(int)));
305
    connect(m_isRelativeCheckbox, SIGNAL(stateChanged(int)),
×
306
            this, SLOT(slotIsRelativeCheckboxChanged(int)));
307

308
    connect(m_xFrequencySpin, SIGNAL(valueChanged(int)),
×
309
            this, SLOT(slotXFrequencySpinChanged(int)));
310
    connect(m_yFrequencySpin, SIGNAL(valueChanged(int)),
×
311
            this, SLOT(slotYFrequencySpinChanged(int)));
312
    connect(m_xPhaseSpin, SIGNAL(valueChanged(int)),
×
313
            this, SLOT(slotXPhaseSpinChanged(int)));
314
    connect(m_yPhaseSpin, SIGNAL(valueChanged(int)),
×
315
            this, SLOT(slotYPhaseSpinChanged(int)));
316

317
    connect(m_colorCheck, SIGNAL(toggled(bool)),
×
318
            this, SLOT(slotSetColorBackground(bool)));
319

320
    redrawPreview();
×
321
}
×
322

323
void EFXEditor::slotTestClicked()
×
324
{
325
    if (m_testButton->isChecked() == true)
×
326
    {
327
        m_efx->start(m_doc->masterTimer(), functionParent());
×
328

329
        //Restart animation so preview it is in sync with real test
330
        m_previewArea->restart();
×
331
    }
332
    else
333
        m_efx->stopAndWait();
×
334
}
×
335

336
void EFXEditor::slotRestartTest()
×
337
{
338
    if (m_testButton->isChecked() == true)
×
339
    {
340
        // Toggle off, toggle on. Duh.
341
        m_testButton->click();
×
342
        m_testButton->click();
×
343
    }
344
}
×
345

346
void EFXEditor::slotModeChanged(Doc::Mode mode)
×
347
{
348
    if (mode == Doc::Operate)
×
349
    {
350
        m_efx->stopAndWait();
×
351
        m_testButton->setChecked(false);
×
352
        m_testButton->setEnabled(false);
×
353
    }
354
    else
355
    {
356
        m_testButton->setEnabled(true);
×
357
    }
358
}
×
359

360
void EFXEditor::slotTabChanged(int tab)
×
361
{
362
    m_efx->setUiStateValue(UI_STATE_TAB_INDEX, tab);
×
363

364
    //When preview animation is opened restart animation but avoid restart if test is running.
365
    if (tab == 1 && (m_testButton->isChecked () == false))
×
366
        m_previewArea->restart ();
×
367
}
×
368

369
void EFXEditor::slotSetColorBackground(bool checked)
×
370
{
371
    m_previewArea->showGradientBackground(checked);
×
372
}
×
373

374
bool EFXEditor::interruptRunning()
×
375
{
376
    if (m_testButton->isChecked() == true)
×
377
    {
378
        m_efx->stopAndWait();
×
379
        m_testButton->setChecked(false);
×
380
        return true;
×
381
    }
382
    else
383
    {
384
        return false;
×
385
    }
386
}
387

388
void EFXEditor::continueRunning(bool running)
×
389
{
390
    if (running == true)
×
391
    {
392
        if (m_doc->mode() == Doc::Operate)
×
393
            m_efx->start(m_doc->masterTimer(), functionParent());
×
394
        else
395
            m_testButton->click();
×
396
    }
397
}
×
398

399
FunctionParent EFXEditor::functionParent() const
×
400
{
401
    return FunctionParent::master();
×
402
}
403

404
/*****************************************************************************
405
 * General page
406
 *****************************************************************************/
407

408
void EFXEditor::updateFixtureTree()
×
409
{
410
    m_tree->clear();
×
411
    QListIterator <EFXFixture*> it(m_efx->fixtures());
×
412
    while (it.hasNext() == true)
×
413
        addFixtureItem(it.next());
×
414
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
415
}
×
416

417
QTreeWidgetItem* EFXEditor::fixtureItem(EFXFixture* ef)
×
418
{
419
    QTreeWidgetItemIterator it(m_tree);
×
420
    while (*it != NULL)
×
421
    {
422
        QTreeWidgetItem* item = *it;
×
423
        EFXFixture* ef_item = reinterpret_cast<EFXFixture*>
424
                              (item->data(0, Qt::UserRole).toULongLong());
×
425
        if (ef_item == ef)
×
426
            return item;
×
427
        ++it;
×
428
    }
429

430
    return NULL;
×
431
}
×
432

433
const QList <EFXFixture*> EFXEditor::selectedFixtures() const
×
434
{
435
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
436
    QList <EFXFixture*> list;
×
437

438
    /* Put all selected fixture IDs to a list and return it */
439
    while (it.hasNext() == true)
×
440
    {
441
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
442
                         (it.next()->data(0, Qt::UserRole).toULongLong());
×
443
        list << ef;
×
444
    }
445

446
    return list;
×
447
}
×
448

449
void EFXEditor::updateIndices(int from, int to)
×
450
{
451
    for (int i = from; i <= to; i++)
×
452
    {
453
        QTreeWidgetItem *item = m_tree->topLevelItem(i);
×
454
        Q_ASSERT(item != NULL);
×
455

456
        item->setText(KColumnNumber,
×
457
                      QString("%1").arg(i + 1, 3, 10, QChar('0')));
×
458
    }
459
}
×
460

461
void EFXEditor::addFixtureItem(EFXFixture* ef)
×
462
{
463
    QTreeWidgetItem* item;
464
    Fixture* fxi;
465

466
    Q_ASSERT(ef != NULL);
×
467

468
    fxi = m_doc->fixture(ef->head().fxi);
×
469
    if (fxi == NULL)
×
470
        return;
×
471

472
    item = new QTreeWidgetItem(m_tree);
×
473

474
    if (fxi->heads() > 1)
×
475
    {
476
        item->setText(KColumnName, QString("%1 [%2]").arg(fxi->name()).arg(ef->head().head));
×
477
    }
478
    else
479
    {
480
        item->setText(KColumnName, fxi->name());
×
481
    }
482
    item->setData(0, Qt::UserRole, QVariant(reinterpret_cast<qulonglong> (ef)));
×
483
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
×
484

485
    if (ef->direction() == Function::Backward)
×
486
        item->setCheckState(KColumnReverse, Qt::Checked);
×
487
    else
488
        item->setCheckState(KColumnReverse, Qt::Unchecked);
×
489

490
    updateModeColumn(item, ef);
×
491
    updateStartOffsetColumn(item, ef);
×
492

493
    updateIndices(m_tree->indexOfTopLevelItem(item),
×
494
                  m_tree->topLevelItemCount() - 1);
×
495

496
    /* Select newly-added fixtures so that they can be moved quickly */
497
    m_tree->setCurrentItem(item);
×
498
}
499

500
void EFXEditor::updateModeColumn(QTreeWidgetItem* item, EFXFixture* ef)
×
501
{
502
    Q_ASSERT(item != NULL);
×
503
    Q_ASSERT(ef != NULL);
×
504

505
    if (m_tree->itemWidget(item, KColumnMode) == NULL)
×
506
    {
507
        QComboBox* combo = new QComboBox(m_tree);
×
508
        combo->setAutoFillBackground(true);
×
509
        combo->addItems(ef->modeList());
×
510
        combo->setProperty(PROPERTY_FIXTURE, (qulonglong) ef);
×
511
        m_tree->setItemWidget(item, KColumnMode, combo);
×
512

513
        const int index = combo->findText(ef->modeToString(ef->mode()));
×
514
        combo->setCurrentIndex(index);
×
515

516
        connect(combo, SIGNAL(currentIndexChanged(int)),
×
517
                this, SLOT(slotFixtureModeChanged(int)));
518
    }
519
}
×
520

521
void EFXEditor::updateStartOffsetColumn(QTreeWidgetItem* item, EFXFixture* ef)
×
522
{
523
    Q_ASSERT(item != NULL);
×
524
    Q_ASSERT(ef != NULL);
×
525

526
    if (m_tree->itemWidget(item, KColumnStartOffset) == NULL)
×
527
    {
528
        QSpinBox* spin = new QSpinBox(m_tree);
×
529
        spin->setAutoFillBackground(true);
×
530
        spin->setRange(0, 359);
×
531
        spin->setValue(ef->startOffset());
×
532
        spin->setSuffix(QChar(0x00b0)); // degree
×
533
        m_tree->setItemWidget(item, KColumnStartOffset, spin);
×
534
        spin->setProperty(PROPERTY_FIXTURE, (qulonglong) ef);
×
535
        connect(spin, SIGNAL(valueChanged(int)),
×
536
                this, SLOT(slotFixtureStartOffsetChanged(int)));
537
    }
538
}
×
539

540
void EFXEditor::removeFixtureItem(EFXFixture* ef)
×
541
{
542
    QTreeWidgetItem* item;
543
    int from;
544

545
    Q_ASSERT(ef != NULL);
×
546

547
    item = fixtureItem(ef);
×
548
    Q_ASSERT(item != NULL);
×
549

550
    from = m_tree->indexOfTopLevelItem(item);
×
551
    delete item;
×
552

553
    updateIndices(from, m_tree->topLevelItemCount() - 1);
×
554
    redrawPreview();
×
555

556
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
557
}
×
558

559
void EFXEditor::slotDialDestroyed(QObject *)
×
560
{
561
    m_speedDial->setChecked(false);
×
562
}
×
563

564
void EFXEditor::createSpeedDials()
×
565
{
566
    if (m_speedDials == NULL)
×
567
    {
568
        m_speedDials = new SpeedDialWidget(this);
×
569
        m_speedDials->setAttribute(Qt::WA_DeleteOnClose);
×
570
        connect(m_speedDials, SIGNAL(fadeInChanged(int)), this, SLOT(slotFadeInChanged(int)));
×
571
        connect(m_speedDials, SIGNAL(fadeOutChanged(int)), this, SLOT(slotFadeOutChanged(int)));
×
572
        connect(m_speedDials, SIGNAL(holdChanged(int)), this, SLOT(slotHoldChanged(int)));
×
573
        connect(m_speedDials, SIGNAL(destroyed(QObject*)), this, SLOT(slotDialDestroyed(QObject*)));
×
574
    }
575

576
    m_speedDials->show();
×
577
}
×
578

579
void EFXEditor::updateSpeedDials()
×
580
{
581
   if (m_speedDial->isChecked() == false)
×
582
        return;
×
583

584
    createSpeedDials();
×
585

586
    m_speedDials->setWindowTitle(m_efx->name());
×
587
    m_speedDials->setFadeInSpeed(m_efx->fadeInSpeed());
×
588
    m_speedDials->setFadeOutSpeed(m_efx->fadeOutSpeed());
×
589
    if ((int)m_efx->duration() < 0)
×
590
        m_speedDials->setDuration(m_efx->duration());
×
591
    else
592
        m_speedDials->setDuration(m_efx->duration() - m_efx->fadeInSpeed() - m_efx->fadeOutSpeed());
×
593
}
594

595
void EFXEditor::slotNameEdited(const QString &text)
×
596
{
597
    m_efx->setName(text);
×
598
    if (m_speedDials)
×
599
        m_speedDials->setWindowTitle(text);
×
600
}
×
601

602
void EFXEditor::slotSpeedDialToggle(bool state)
×
603
{
604
    if (state == true)
×
605
    {
606
        updateSpeedDials();
×
607
    }
608
    else
609
    {
610
        if (m_speedDials != NULL)
×
611
            m_speedDials->deleteLater();
×
612
        m_speedDials = NULL;
×
613
    }
614

615
    m_efx->setUiStateValue(UI_STATE_SHOW_DIAL, state);
×
616
}
×
617

618
void EFXEditor::slotFixtureItemChanged(QTreeWidgetItem* item, int column)
×
619
{
620
    if (column == KColumnReverse)
×
621
    {
622
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
623
                         (item->data(0, Qt::UserRole).toULongLong());
×
624
        Q_ASSERT(ef != NULL);
×
625

626
        if (item->checkState(column) == Qt::Checked)
×
627
            ef->setDirection(Function::Backward);
×
628
        else
629
            ef->setDirection(Function::Forward);
×
630

631
        redrawPreview();
×
632
    }
633
}
×
634

635
void EFXEditor::slotFixtureModeChanged(int index)
×
636
{
637
    QComboBox *combo = qobject_cast<QComboBox*>(QObject::sender());
×
638
    Q_ASSERT(combo != NULL);
×
639

640
    EFXFixture *ef = (EFXFixture*) combo->property(PROPERTY_FIXTURE).toULongLong();
×
641
    Q_ASSERT(ef != NULL);
×
642

643
    ef->setMode(ef->stringToMode (combo->itemText(index)));
×
644

645
    // Restart the test after the latest mode change, delayed
646
    m_testTimer.start();
×
647
}
×
648

649
void EFXEditor::slotFixtureStartOffsetChanged(int startOffset)
×
650
{
651
    QSpinBox *spin = qobject_cast<QSpinBox*>(QObject::sender());
×
652
    Q_ASSERT(spin != NULL);
×
653
    EFXFixture *ef = (EFXFixture*) spin->property(PROPERTY_FIXTURE).toULongLong();
×
654
    Q_ASSERT(ef != NULL);
×
655
    ef->setStartOffset(startOffset);
×
656

657
    redrawPreview();
×
658

659
    // Restart the test after the latest offset change, delayed
660
    m_testTimer.start();
×
661
}
×
662

663
void EFXEditor::slotAddFixtureClicked()
×
664
{
665
    /* The following code is the original QLC+ code (EFX with only Pan-Tilt).
666
     * Now, with modes, the same fixture could be duplicated. */
667

668
    /* Put all fixtures already present into a list of fixtures that
669
       will be disabled in the fixture selection dialog */
670
    QList <GroupHead> disabled;
×
671
    QTreeWidgetItemIterator twit(m_tree);
×
672
    /*
673
    while (*twit != NULL)
674
    {
675
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
676
                         ((*twit)->data(0, Qt::UserRole).toULongLong());
677
        Q_ASSERT(ef != NULL);
678

679
        disabled.append(ef->head());
680
        twit++;
681
    }
682
    */
683

684
    /* Disable all fixtures that don't have pan OR tilt, dimmer or RGB channels */
685
    /*
686
    QListIterator <Fixture*> fxit(m_doc->fixtures());
687
    while (fxit.hasNext() == true)
688
    {
689
        Fixture* fixture(fxit.next());
690
        Q_ASSERT(fixture != NULL);
691

692
        // If a channel with pan or tilt group exists, don't disable this fixture
693
        if (fixture->channel(QLCChannel::Pan) == QLCChannel::invalid() &&
694
            fixture->channel(QLCChannel::Tilt) == QLCChannel::invalid())
695
        {
696
            // Disable all fixtures without pan or tilt channels
697
            disabled << fixture->id();
698
        }
699
        else
700
        {
701
            QVector <QLCFixtureHead> const& heads = fixture->fixtureMode()->heads();
702
            for (int i = 0; i < heads.size(); ++i)
703
            {
704
                if (heads[i].panMsbChannel() == QLCChannel::invalid() &&
705
                    heads[i].tiltMsbChannel() == QLCChannel::invalid() &&
706
                    heads[i].panLsbChannel() == QLCChannel::invalid() &&
707
                    heads[i].tiltLsbChannel() == QLCChannel::invalid())
708
                {
709
                    // Disable heads without pan or tilt channels
710
                    disabled << GroupHead(fixture->id(), i);
711
                }
712
            }
713
        }
714
    }
715
    */
716

717
    FixtureSelection fs(this, m_doc);
×
718
    fs.setMultiSelection(true);
×
719
    fs.setSelectionMode(FixtureSelection::Heads);
×
720
    fs.setDisabledHeads(disabled);
×
721
    if (fs.exec() == QDialog::Accepted)
×
722
    {
723
        // Stop running while adding fixtures
724
        bool running = interruptRunning();
×
725

726
        QListIterator <GroupHead> it(fs.selectedHeads());
×
727
        while (it.hasNext() == true)
×
728
        {
729
            EFXFixture* ef = new EFXFixture(m_efx);
×
730
            ef->setHead(it.next());
×
731

732
            if (m_efx->addFixture(ef) == true)
×
733
                addFixtureItem(ef);
×
734
            else
735
                delete ef;
×
736
        }
737

738
        m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
739

740
        redrawPreview();
×
741

742
        // Continue running if appropriate
743
        continueRunning(running);
×
744
    }
×
745
}
×
746

747
void EFXEditor::slotRemoveFixtureClicked()
×
748
{
749
    int r = QMessageBox::question(
×
750
                this, tr("Remove fixtures"),
×
751
                tr("Do you want to remove the selected fixture(s)?"),
×
752
                QMessageBox::Yes, QMessageBox::No);
753

754
    if (r == QMessageBox::Yes)
×
755
    {
756
        // Stop running while removing fixtures
757
        bool running = interruptRunning();
×
758

759
        QListIterator <EFXFixture*> it(selectedFixtures());
×
760
        while (it.hasNext() == true)
×
761
        {
762
            EFXFixture* ef = it.next();
×
763
            Q_ASSERT(ef != NULL);
×
764

765
            removeFixtureItem(ef);
×
766
            if (m_efx->removeFixture(ef) == true)
×
767
                delete ef;
×
768
        }
769

770
        redrawPreview();
×
771

772
        // Continue if appropriate
773
        continueRunning(running);
×
774
    }
×
775
}
×
776

777
void EFXEditor::slotRaiseFixtureClicked()
×
778
{
779
    // Stop running while moving fixtures
780
    bool running = interruptRunning();
×
781

782
    QTreeWidgetItem* item = m_tree->currentItem();
×
783
    if (item != NULL)
×
784
    {
785
        int index = m_tree->indexOfTopLevelItem(item);
×
786
        if (index == 0)
×
787
            return;
×
788

789
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
790
                         (item->data(0, Qt::UserRole).toULongLong());
×
791
        Q_ASSERT(ef != NULL);
×
792

793
        if (m_efx->raiseFixture(ef) == true)
×
794
        {
795
            item = m_tree->takeTopLevelItem(index);
×
796

797
            m_tree->insertTopLevelItem(index - 1, item);
×
798

799
            updateModeColumn(item, ef);
×
800
            updateStartOffsetColumn(item, ef);
×
801
            updateIndices(index - 1, index);
×
802
            m_tree->setCurrentItem(item);
×
803

804
            redrawPreview();
×
805
        }
806
    }
807

808
    // Continue running if appropriate
809
    continueRunning(running);
×
810
}
811

812
void EFXEditor::slotLowerFixtureClicked()
×
813
{
814
    // Stop running while moving fixtures
815
    bool running = interruptRunning();
×
816

817
    QTreeWidgetItem* item = m_tree->currentItem();
×
818
    if (item != NULL)
×
819
    {
820
        int index = m_tree->indexOfTopLevelItem(item);
×
821
        if (index == (m_tree->topLevelItemCount() - 1))
×
822
            return;
×
823

824
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
825
                         (item->data(0, Qt::UserRole).toULongLong());
×
826
        Q_ASSERT(ef != NULL);
×
827

828
        if (m_efx->lowerFixture(ef) == true)
×
829
        {
830
            item = m_tree->takeTopLevelItem(index);
×
831
            m_tree->insertTopLevelItem(index + 1, item);
×
832

833
            updateModeColumn(item, ef);
×
834
            updateStartOffsetColumn(item, ef);
×
835
            updateIndices(index, index + 1);
×
836
            m_tree->setCurrentItem(item);
×
837

838
            redrawPreview();
×
839
        }
840
    }
841

842
    // Continue running if appropriate
843
    continueRunning(running);
×
844
}
845

846
void EFXEditor::slotParallelRadioToggled(bool state)
×
847
{
848
    Q_ASSERT(m_efx != NULL);
×
849
    if (state == true)
×
850
    {
851
        m_efx->setPropagationMode(EFX::Parallel);
×
852
        redrawPreview();
×
853
    }
854
}
×
855

856
void EFXEditor::slotSerialRadioToggled(bool state)
×
857
{
858
    Q_ASSERT(m_efx != NULL);
×
859
    if (state == true)
×
860
    {
861

862
        m_efx->setPropagationMode(EFX::Serial);
×
863
        redrawPreview();
×
864
    }
865
}
×
866

867
void EFXEditor::slotAsymmetricRadioToggled(bool state)
×
868
{
869
    Q_ASSERT(m_efx != NULL);
×
870
    if (state == true)
×
871
    {
872

873
        m_efx->setPropagationMode(EFX::Asymmetric);
×
874
        redrawPreview();
×
875
    }
876
}
×
877

878
void EFXEditor::slotFadeInChanged(int ms)
×
879
{
880
    m_efx->setFadeInSpeed(ms);
×
881
    slotRestartTest();
×
882
}
×
883

884
void EFXEditor::slotFadeOutChanged(int ms)
×
885
{
886
    m_efx->setFadeOutSpeed(ms);
×
887
}
×
888

889
void EFXEditor::slotHoldChanged(int ms)
×
890
{
891
    uint duration = 0;
×
892
    if (ms < 0)
×
893
        duration = ms;
×
894
    else
895
        duration = m_efx->fadeInSpeed() + ms + m_efx->fadeOutSpeed();
×
896
    m_efx->setDuration(duration);
×
897
    redrawPreview();
×
898
}
×
899

900
void EFXEditor::slotFixtureRemoved()
×
901
{
902
    // EFX already catches fixture removals so just update the list
903
    updateFixtureTree();
×
904
    redrawPreview();
×
905
}
×
906

907
void EFXEditor::slotFixtureChanged()
×
908
{
909
    // Update the tree in case fixture's name changes
910
    updateFixtureTree();
×
911
}
×
912

913
/*****************************************************************************
914
 * Movement page
915
 *****************************************************************************/
916

917
void EFXEditor::slotAlgorithmSelected(int algoIndex)
×
918
{
919
    Q_ASSERT(m_efx != NULL);
×
920

921
    m_efx->setAlgorithm(EFX::Algorithm(algoIndex));
×
922

923
    if (m_efx->isFrequencyEnabled())
×
924
    {
925
        m_xFrequencyLabel->setEnabled(true);
×
926
        m_yFrequencyLabel->setEnabled(true);
×
927

928
        m_xFrequencySpin->setEnabled(true);
×
929
        m_yFrequencySpin->setEnabled(true);
×
930
    }
931
    else
932
    {
933
        m_xFrequencyLabel->setEnabled(false);
×
934
        m_yFrequencyLabel->setEnabled(false);
×
935

936
        m_xFrequencySpin->setEnabled(false);
×
937
        m_yFrequencySpin->setEnabled(false);
×
938
    }
939

940
    if (m_efx->isPhaseEnabled())
×
941
    {
942
        m_xPhaseLabel->setEnabled(true);
×
943
        m_yPhaseLabel->setEnabled(true);
×
944

945
        m_xPhaseSpin->setEnabled(true);
×
946
        m_yPhaseSpin->setEnabled(true);
×
947
    }
948
    else
949
    {
950
        m_xPhaseLabel->setEnabled(false);
×
951
        m_yPhaseLabel->setEnabled(false);
×
952

953
        m_xPhaseSpin->setEnabled(false);
×
954
        m_yPhaseSpin->setEnabled(false);
×
955
    }
956

957
    redrawPreview();
×
958
}
×
959

960
void EFXEditor::slotWidthSpinChanged(int value)
×
961
{
962
    Q_ASSERT(m_efx != NULL);
×
963
    m_efx->setWidth(value);
×
964
    redrawPreview();
×
965
}
×
966

967
void EFXEditor::slotHeightSpinChanged(int value)
×
968
{
969
    Q_ASSERT(m_efx != NULL);
×
970
    m_efx->setHeight(value);
×
971
    redrawPreview();
×
972
}
×
973

974
void EFXEditor::slotRotationSpinChanged(int value)
×
975
{
976
    Q_ASSERT(m_efx != NULL);
×
977
    m_efx->setRotation(value);
×
978
    redrawPreview();
×
979
}
×
980

981
void EFXEditor::slotStartOffsetSpinChanged(int value)
×
982
{
983
    Q_ASSERT(m_efx != NULL);
×
984
    m_efx->setStartOffset(value);
×
985
    redrawPreview();
×
986
}
×
987

988
void EFXEditor::slotIsRelativeCheckboxChanged(int value)
×
989
{
990
    Q_ASSERT(m_efx != NULL);
×
991
    m_efx->setIsRelative(value == Qt::Checked);
×
992
}
×
993

994
void EFXEditor::slotXOffsetSpinChanged(int value)
×
995
{
996
    Q_ASSERT(m_efx != NULL);
×
997
    m_efx->setXOffset(value);
×
998
    redrawPreview();
×
999
}
×
1000

1001
void EFXEditor::slotYOffsetSpinChanged(int value)
×
1002
{
1003
    Q_ASSERT(m_efx != NULL);
×
1004
    m_efx->setYOffset(value);
×
1005
    redrawPreview();
×
1006
}
×
1007

1008
void EFXEditor::slotXFrequencySpinChanged(int value)
×
1009
{
1010
    Q_ASSERT(m_efx != NULL);
×
1011
    m_efx->setXFrequency(value);
×
1012
    redrawPreview();
×
1013
}
×
1014

1015
void EFXEditor::slotYFrequencySpinChanged(int value)
×
1016
{
1017
    Q_ASSERT(m_efx != NULL);
×
1018
    m_efx->setYFrequency(value);
×
1019
    redrawPreview();
×
1020
}
×
1021

1022
void EFXEditor::slotXPhaseSpinChanged(int value)
×
1023
{
1024
    Q_ASSERT(m_efx != NULL);
×
1025
    m_efx->setXPhase(value);
×
1026
    redrawPreview();
×
1027
}
×
1028

1029
void EFXEditor::slotYPhaseSpinChanged(int value)
×
1030
{
1031
    Q_ASSERT(m_efx != NULL);
×
1032
    m_efx->setYPhase(value);
×
1033
    redrawPreview();
×
1034
}
×
1035

1036
void EFXEditor::slotDimmerControlToggled(bool checked)
×
1037
{
1038
    Q_ASSERT(m_efx != NULL);
×
1039
    m_efx->setDimmerControlEnabled(checked);
×
1040
}
×
1041

1042
/*****************************************************************************
1043
 * Run order
1044
 *****************************************************************************/
1045

1046
void EFXEditor::slotLoopClicked()
×
1047
{
1048
    Q_ASSERT(m_efx != NULL);
×
1049
    m_efx->setRunOrder(Function::Loop);
×
1050
}
×
1051

1052
void EFXEditor::slotSingleShotClicked()
×
1053
{
1054
    Q_ASSERT(m_efx != NULL);
×
1055
    m_efx->setRunOrder(Function::SingleShot);
×
1056
}
×
1057

1058
void EFXEditor::slotPingPongClicked()
×
1059
{
1060
    Q_ASSERT(m_efx != NULL);
×
1061
    m_efx->setRunOrder(Function::PingPong);
×
1062
}
×
1063

1064
/*****************************************************************************
1065
 * Direction
1066
 *****************************************************************************/
1067

1068
void EFXEditor::slotForwardClicked()
×
1069
{
1070
    Q_ASSERT(m_efx != NULL);
×
1071
    m_efx->setDirection(Function::Forward);
×
1072
    redrawPreview();
×
1073
}
×
1074

1075
void EFXEditor::slotBackwardClicked()
×
1076
{
1077
    Q_ASSERT(m_efx != NULL);
×
1078
    m_efx->setDirection(Function::Backward);
×
1079
    redrawPreview();
×
1080
}
×
1081

1082
void EFXEditor::redrawPreview()
×
1083
{
1084
    if (m_previewArea == NULL)
×
1085
        return;
×
1086

1087
    QPolygonF polygon;
×
1088
    m_efx->preview(polygon);
×
1089

1090
    QVector <QPolygonF> fixturePoints;
×
1091
    m_efx->previewFixtures(fixturePoints);
×
1092

1093
    m_previewArea->setPolygon(polygon);
×
1094
    m_previewArea->setFixturePolygons(fixturePoints);
×
1095

1096
    m_previewArea->draw(m_efx->duration() / polygon.size());
×
1097
}
×
1098

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