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

mcallegari / qlcplus / 13633248611

03 Mar 2025 02:31PM UTC coverage: 31.871% (+0.4%) from 31.5%
13633248611

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 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 <QPainter>
31
#include <QLabel>
32
#include <QDebug>
33
#include <QPen>
34

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

42
#define SETTINGS_GEOMETRY "efxeditor/geometry"
43

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

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

54
#define KTabGeneral 0
55
#define KTabMovement 1
56

57
/*****************************************************************************
58
 * Initialization
59
 *****************************************************************************/
60

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

72
    setupUi(this);
×
73

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

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

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

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

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

96
    updateSpeedDials();
×
97

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

235
    /* Running order */
236
    switch (m_efx->runOrder())
×
237
    {
238
        default:
×
239
        case Function::Loop:
240
            m_loop->setChecked(true);
×
241
        break;
242
        case Function::SingleShot:
×
243
            m_singleShot->setChecked(true);
×
244
        break;
245
        case Function::PingPong:
×
246
            m_pingPong->setChecked(true);
×
247
        break;
248
    }
249

250
    /* Direction */
251
    switch (m_efx->direction())
×
252
    {
253
        default:
×
254
        case Function::Forward:
255
            m_forward->setChecked(true);
×
256
        break;
257
        case Function::Backward:
×
258
            m_backward->setChecked(true);
×
259
        break;
260
    }
261

262
    connect(m_loop, SIGNAL(clicked()),
×
263
            this, SLOT(slotLoopClicked()));
264
    connect(m_singleShot, SIGNAL(clicked()),
×
265
            this, SLOT(slotSingleShotClicked()));
266
    connect(m_pingPong, SIGNAL(clicked()),
×
267
            this, SLOT(slotPingPongClicked()));
268

269
    connect(m_forward, SIGNAL(clicked()),
×
270
            this, SLOT(slotForwardClicked()));
271
    connect(m_backward, SIGNAL(clicked()),
×
272
            this, SLOT(slotBackwardClicked()));
273

274
    connect(m_algorithmCombo, SIGNAL(activated(int)),
×
275
            this, SLOT(slotAlgorithmSelected(int)));
276
    connect(m_widthSpin, SIGNAL(valueChanged(int)),
×
277
            this, SLOT(slotWidthSpinChanged(int)));
278
    connect(m_heightSpin, SIGNAL(valueChanged(int)),
×
279
            this, SLOT(slotHeightSpinChanged(int)));
280
    connect(m_xOffsetSpin, SIGNAL(valueChanged(int)),
×
281
            this, SLOT(slotXOffsetSpinChanged(int)));
282
    connect(m_yOffsetSpin, SIGNAL(valueChanged(int)),
×
283
            this, SLOT(slotYOffsetSpinChanged(int)));
284
    connect(m_rotationSpin, SIGNAL(valueChanged(int)),
×
285
            this, SLOT(slotRotationSpinChanged(int)));
286
    connect(m_startOffsetSpin, SIGNAL(valueChanged(int)),
×
287
            this, SLOT(slotStartOffsetSpinChanged(int)));
288
    connect(m_isRelativeCheckbox, SIGNAL(stateChanged(int)),
×
289
            this, SLOT(slotIsRelativeCheckboxChanged(int)));
290

291
    connect(m_xFrequencySpin, SIGNAL(valueChanged(int)),
×
292
            this, SLOT(slotXFrequencySpinChanged(int)));
293
    connect(m_yFrequencySpin, SIGNAL(valueChanged(int)),
×
294
            this, SLOT(slotYFrequencySpinChanged(int)));
295
    connect(m_xPhaseSpin, SIGNAL(valueChanged(int)),
×
296
            this, SLOT(slotXPhaseSpinChanged(int)));
297
    connect(m_yPhaseSpin, SIGNAL(valueChanged(int)),
×
298
            this, SLOT(slotYPhaseSpinChanged(int)));
299

300
    connect(m_colorCheck, SIGNAL(toggled(bool)),
×
301
            this, SLOT(slotSetColorBackground(bool)));
302

303
    redrawPreview();
×
304
}
×
305

306
void EFXEditor::slotTestClicked()
×
307
{
308
    if (m_testButton->isChecked() == true)
×
309
    {
310
        m_efx->start(m_doc->masterTimer(), functionParent());
×
311

312
        //Restart animation so preview it is in sync with real test
313
        m_previewArea->restart();
×
314
    }
315
    else
316
        m_efx->stopAndWait();
×
317
}
×
318

319
void EFXEditor::slotRestartTest()
×
320
{
321
    if (m_testButton->isChecked() == true)
×
322
    {
323
        // Toggle off, toggle on. Duh.
324
        m_testButton->click();
×
325
        m_testButton->click();
×
326
    }
327
}
×
328

329
void EFXEditor::slotModeChanged(Doc::Mode mode)
×
330
{
331
    if (mode == Doc::Operate)
×
332
    {
333
        m_efx->stopAndWait();
×
334
        m_testButton->setChecked(false);
×
335
        m_testButton->setEnabled(false);
×
336
    }
337
    else
338
    {
339
        m_testButton->setEnabled(true);
×
340
    }
341
}
×
342

343
void EFXEditor::slotTabChanged(int tab)
×
344
{
345
    m_efx->setUiStateValue(UI_STATE_TAB_INDEX, tab);
×
346

347
    //When preview animation is opened restart animation but avoid restart if test is running.
348
    if (tab == 1 && (m_testButton->isChecked () == false))
×
349
        m_previewArea->restart ();
×
350
}
×
351

352
void EFXEditor::slotSetColorBackground(bool checked)
×
353
{
354
    m_previewArea->showGradientBackground(checked);
×
355
}
×
356

357
bool EFXEditor::interruptRunning()
×
358
{
359
    if (m_testButton->isChecked() == true)
×
360
    {
361
        m_efx->stopAndWait();
×
362
        m_testButton->setChecked(false);
×
363
        return true;
×
364
    }
365
    else
366
    {
367
        return false;
368
    }
369
}
370

371
void EFXEditor::continueRunning(bool running)
×
372
{
373
    if (running == true)
×
374
    {
375
        if (m_doc->mode() == Doc::Operate)
×
376
            m_efx->start(m_doc->masterTimer(), functionParent());
×
377
        else
378
            m_testButton->click();
×
379
    }
380
}
×
381

382
FunctionParent EFXEditor::functionParent() const
×
383
{
384
    return FunctionParent::master();
×
385
}
386

387
/*****************************************************************************
388
 * General page
389
 *****************************************************************************/
390

391
void EFXEditor::updateFixtureTree()
×
392
{
393
    m_tree->clear();
×
394
    QListIterator <EFXFixture*> it(m_efx->fixtures());
×
395
    while (it.hasNext() == true)
×
396
        addFixtureItem(it.next());
×
397
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
398
}
×
399

400
QTreeWidgetItem* EFXEditor::fixtureItem(EFXFixture* ef)
×
401
{
402
    QTreeWidgetItemIterator it(m_tree);
×
403
    while (*it != NULL)
×
404
    {
405
        QTreeWidgetItem* item = *it;
406
        EFXFixture* ef_item = reinterpret_cast<EFXFixture*>
407
                              (item->data(0, Qt::UserRole).toULongLong());
×
408
        if (ef_item == ef)
×
409
            return item;
×
410
        ++it;
×
411
    }
412

413
    return NULL;
414
}
×
415

416
const QList <EFXFixture*> EFXEditor::selectedFixtures() const
×
417
{
418
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
419
    QList <EFXFixture*> list;
420

421
    /* Put all selected fixture IDs to a list and return it */
422
    while (it.hasNext() == true)
×
423
    {
424
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
425
                         (it.next()->data(0, Qt::UserRole).toULongLong());
×
426
        list << ef;
427
    }
428

429
    return list;
×
430
}
×
431

432
void EFXEditor::updateIndices(int from, int to)
×
433
{
434
    for (int i = from; i <= to; i++)
×
435
    {
436
        QTreeWidgetItem *item = m_tree->topLevelItem(i);
×
437
        Q_ASSERT(item != NULL);
438

439
        item->setText(KColumnNumber,
×
440
                      QString("%1").arg(i + 1, 3, 10, QChar('0')));
×
441
    }
442
}
×
443

444
void EFXEditor::addFixtureItem(EFXFixture* ef)
×
445
{
446
    QTreeWidgetItem* item;
447
    Fixture* fxi;
448

449
    Q_ASSERT(ef != NULL);
450

451
    fxi = m_doc->fixture(ef->head().fxi);
×
452
    if (fxi == NULL)
×
453
        return;
454

455
    item = new QTreeWidgetItem(m_tree);
×
456

457
    if (fxi->heads() > 1)
×
458
    {
459
        item->setText(KColumnName, QString("%1 [%2]").arg(fxi->name()).arg(ef->head().head));
×
460
    }
461
    else
462
    {
463
        item->setText(KColumnName, fxi->name());
×
464
    }
465
    item->setData(0, Qt::UserRole, QVariant(reinterpret_cast<qulonglong> (ef)));
×
466
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
×
467

468
    if (ef->direction() == Function::Backward)
×
469
        item->setCheckState(KColumnReverse, Qt::Checked);
×
470
    else
471
        item->setCheckState(KColumnReverse, Qt::Unchecked);
×
472

473
    updateModeColumn(item, ef);
×
474
    updateStartOffsetColumn(item, ef);
×
475

476
    updateIndices(m_tree->indexOfTopLevelItem(item),
×
477
                  m_tree->topLevelItemCount() - 1);
×
478

479
    /* Select newly-added fixtures so that they can be moved quickly */
480
    m_tree->setCurrentItem(item);
×
481
}
482

483
void EFXEditor::updateModeColumn(QTreeWidgetItem* item, EFXFixture* ef)
×
484
{
485
    Q_ASSERT(item != NULL);
486
    Q_ASSERT(ef != NULL);
487

488
    if (m_tree->itemWidget(item, KColumnMode) == NULL)
×
489
    {
490
        QComboBox* combo = new QComboBox(m_tree);
×
491
        combo->setAutoFillBackground(true);
×
492
        combo->addItems(ef->modeList());
×
493
        combo->setProperty(PROPERTY_FIXTURE, (qulonglong) ef);
×
494
        m_tree->setItemWidget(item, KColumnMode, combo);
×
495

496
        const int index = combo->findText(ef->modeToString(ef->mode()));
×
497
        combo->setCurrentIndex(index);
×
498

499
        connect(combo, SIGNAL(currentIndexChanged(int)),
×
500
                this, SLOT(slotFixtureModeChanged(int)));
501
    }
502
}
×
503

504
void EFXEditor::updateStartOffsetColumn(QTreeWidgetItem* item, EFXFixture* ef)
×
505
{
506
    Q_ASSERT(item != NULL);
507
    Q_ASSERT(ef != NULL);
508

509
    if (m_tree->itemWidget(item, KColumnStartOffset) == NULL)
×
510
    {
511
        QSpinBox* spin = new QSpinBox(m_tree);
×
512
        spin->setAutoFillBackground(true);
×
513
        spin->setRange(0, 359);
×
514
        spin->setValue(ef->startOffset());
×
515
        spin->setSuffix(QChar(0x00b0)); // degree
×
516
        m_tree->setItemWidget(item, KColumnStartOffset, spin);
×
517
        spin->setProperty(PROPERTY_FIXTURE, (qulonglong) ef);
×
518
        connect(spin, SIGNAL(valueChanged(int)),
×
519
                this, SLOT(slotFixtureStartOffsetChanged(int)));
520
    }
521
}
×
522

523
void EFXEditor::removeFixtureItem(EFXFixture* ef)
×
524
{
525
    QTreeWidgetItem* item;
526
    int from;
527

528
    Q_ASSERT(ef != NULL);
529

530
    item = fixtureItem(ef);
×
531
    Q_ASSERT(item != NULL);
532

533
    from = m_tree->indexOfTopLevelItem(item);
×
534
    delete item;
×
535

536
    updateIndices(from, m_tree->topLevelItemCount() - 1);
×
537
    redrawPreview();
×
538

539
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
540
}
×
541

542
void EFXEditor::slotDialDestroyed(QObject *)
×
543
{
544
    m_speedDial->setChecked(false);
×
545
}
×
546

547
void EFXEditor::createSpeedDials()
×
548
{
549
    if (m_speedDials == NULL)
×
550
    {
551
        m_speedDials = new SpeedDialWidget(this);
×
552
        m_speedDials->setAttribute(Qt::WA_DeleteOnClose);
×
553
        connect(m_speedDials, SIGNAL(fadeInChanged(int)), this, SLOT(slotFadeInChanged(int)));
×
554
        connect(m_speedDials, SIGNAL(fadeOutChanged(int)), this, SLOT(slotFadeOutChanged(int)));
×
555
        connect(m_speedDials, SIGNAL(holdChanged(int)), this, SLOT(slotHoldChanged(int)));
×
556
        connect(m_speedDials, SIGNAL(destroyed(QObject*)), this, SLOT(slotDialDestroyed(QObject*)));
×
557
    }
558

559
    m_speedDials->show();
×
560
}
×
561

562
void EFXEditor::updateSpeedDials()
×
563
{
564
   if (m_speedDial->isChecked() == false)
×
565
        return;
566

567
    createSpeedDials();
×
568

569
    m_speedDials->setWindowTitle(m_efx->name());
×
570
    m_speedDials->setFadeInSpeed(m_efx->fadeInSpeed());
×
571
    m_speedDials->setFadeOutSpeed(m_efx->fadeOutSpeed());
×
572
    if ((int)m_efx->duration() < 0)
×
573
        m_speedDials->setDuration(m_efx->duration());
×
574
    else
575
        m_speedDials->setDuration(m_efx->duration() - m_efx->fadeInSpeed() - m_efx->fadeOutSpeed());
×
576
}
577

578
void EFXEditor::slotNameEdited(const QString &text)
×
579
{
580
    m_efx->setName(text);
×
581
    if (m_speedDials)
×
582
        m_speedDials->setWindowTitle(text);
×
583
}
×
584

585
void EFXEditor::slotSpeedDialToggle(bool state)
×
586
{
587
    if (state == true)
×
588
    {
589
        updateSpeedDials();
×
590
    }
591
    else
592
    {
593
        if (m_speedDials != NULL)
×
594
            m_speedDials->deleteLater();
×
595
        m_speedDials = NULL;
×
596
    }
597

598
    m_efx->setUiStateValue(UI_STATE_SHOW_DIAL, state);
×
599
}
×
600

601
void EFXEditor::slotFixtureItemChanged(QTreeWidgetItem* item, int column)
×
602
{
603
    if (column == KColumnReverse)
×
604
    {
605
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
606
                         (item->data(0, Qt::UserRole).toULongLong());
×
607
        Q_ASSERT(ef != NULL);
608

609
        if (item->checkState(column) == Qt::Checked)
×
610
            ef->setDirection(Function::Backward);
×
611
        else
612
            ef->setDirection(Function::Forward);
×
613

614
        redrawPreview();
×
615
    }
616
}
×
617

618
void EFXEditor::slotFixtureModeChanged(int index)
×
619
{
620
    QComboBox *combo = qobject_cast<QComboBox*>(QObject::sender());
×
621
    Q_ASSERT(combo != NULL);
622

623
    EFXFixture *ef = (EFXFixture*) combo->property(PROPERTY_FIXTURE).toULongLong();
×
624
    Q_ASSERT(ef != NULL);
625

626
    ef->setMode(ef->stringToMode (combo->itemText(index)));
×
627

628
    // Restart the test after the latest mode change, delayed
629
    m_testTimer.start();
×
630
}
×
631

632
void EFXEditor::slotFixtureStartOffsetChanged(int startOffset)
×
633
{
634
    QSpinBox *spin = qobject_cast<QSpinBox*>(QObject::sender());
×
635
    Q_ASSERT(spin != NULL);
636
    EFXFixture *ef = (EFXFixture*) spin->property(PROPERTY_FIXTURE).toULongLong();
×
637
    Q_ASSERT(ef != NULL);
638
    ef->setStartOffset(startOffset);
×
639

640
    redrawPreview();
×
641

642
    // Restart the test after the latest offset change, delayed
643
    m_testTimer.start();
×
644
}
×
645

646
void EFXEditor::slotAddFixtureClicked()
×
647
{
648
    /* The following code is the original QLC+ code (EFX with only Pan-Tilt).
649
     * Now, with modes, the same fixture could be duplicated. */
650

651
    /* Put all fixtures already present into a list of fixtures that
652
       will be disabled in the fixture selection dialog */
653
    QList <GroupHead> disabled;
654
    QTreeWidgetItemIterator twit(m_tree);
×
655
    /*
656
    while (*twit != NULL)
657
    {
658
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
659
                         ((*twit)->data(0, Qt::UserRole).toULongLong());
660
        Q_ASSERT(ef != NULL);
661

662
        disabled.append(ef->head());
663
        twit++;
664
    }
665
    */
666

667
    /* Disable all fixtures that don't have pan OR tilt, dimmer or RGB channels */
668
    /*
669
    QListIterator <Fixture*> fxit(m_doc->fixtures());
670
    while (fxit.hasNext() == true)
671
    {
672
        Fixture* fixture(fxit.next());
673
        Q_ASSERT(fixture != NULL);
674

675
        // If a channel with pan or tilt group exists, don't disable this fixture
676
        if (fixture->channel(QLCChannel::Pan) == QLCChannel::invalid() &&
677
            fixture->channel(QLCChannel::Tilt) == QLCChannel::invalid())
678
        {
679
            // Disable all fixtures without pan or tilt channels
680
            disabled << fixture->id();
681
        }
682
        else
683
        {
684
            QVector <QLCFixtureHead> const& heads = fixture->fixtureMode()->heads();
685
            for (int i = 0; i < heads.size(); ++i)
686
            {
687
                if (heads[i].panMsbChannel() == QLCChannel::invalid() &&
688
                    heads[i].tiltMsbChannel() == QLCChannel::invalid() &&
689
                    heads[i].panLsbChannel() == QLCChannel::invalid() &&
690
                    heads[i].tiltLsbChannel() == QLCChannel::invalid())
691
                {
692
                    // Disable heads without pan or tilt channels
693
                    disabled << GroupHead(fixture->id(), i);
694
                }
695
            }
696
        }
697
    }
698
    */
699

700
    FixtureSelection fs(this, m_doc);
×
701
    fs.setMultiSelection(true);
×
702
    fs.setSelectionMode(FixtureSelection::Heads);
×
703
    fs.setDisabledHeads(disabled);
×
704
    if (fs.exec() == QDialog::Accepted)
×
705
    {
706
        // Stop running while adding fixtures
707
        bool running = interruptRunning();
×
708

709
        QListIterator <GroupHead> it(fs.selectedHeads());
×
710
        while (it.hasNext() == true)
×
711
        {
712
            EFXFixture* ef = new EFXFixture(m_efx);
×
713
            ef->setHead(it.next());
×
714

715
            if (m_efx->addFixture(ef) == true)
×
716
                addFixtureItem(ef);
×
717
            else
718
                delete ef;
×
719
        }
720

721
        m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
722

723
        redrawPreview();
×
724

725
        // Continue running if appropriate
726
        continueRunning(running);
×
727
    }
728
}
×
729

730
void EFXEditor::slotRemoveFixtureClicked()
×
731
{
732
    int r = QMessageBox::question(
×
733
                this, tr("Remove fixtures"),
×
734
                tr("Do you want to remove the selected fixture(s)?"),
×
735
                QMessageBox::Yes, QMessageBox::No);
736

737
    if (r == QMessageBox::Yes)
×
738
    {
739
        // Stop running while removing fixtures
740
        bool running = interruptRunning();
×
741

742
        QListIterator <EFXFixture*> it(selectedFixtures());
×
743
        while (it.hasNext() == true)
×
744
        {
745
            EFXFixture* ef = it.next();
×
746
            Q_ASSERT(ef != NULL);
747

748
            removeFixtureItem(ef);
×
749
            if (m_efx->removeFixture(ef) == true)
×
750
                delete ef;
×
751
        }
752

753
        redrawPreview();
×
754

755
        // Continue if appropriate
756
        continueRunning(running);
×
757
    }
758
}
×
759

760
void EFXEditor::slotRaiseFixtureClicked()
×
761
{
762
    // Stop running while moving fixtures
763
    bool running = interruptRunning();
×
764

765
    QTreeWidgetItem* item = m_tree->currentItem();
×
766
    if (item != NULL)
×
767
    {
768
        int index = m_tree->indexOfTopLevelItem(item);
×
769
        if (index == 0)
×
770
            return;
771

772
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
773
                         (item->data(0, Qt::UserRole).toULongLong());
×
774
        Q_ASSERT(ef != NULL);
775

776
        if (m_efx->raiseFixture(ef) == true)
×
777
        {
778
            item = m_tree->takeTopLevelItem(index);
×
779

780
            m_tree->insertTopLevelItem(index - 1, item);
×
781

782
            updateModeColumn(item, ef);
×
783
            updateStartOffsetColumn(item, ef);
×
784
            updateIndices(index - 1, index);
×
785
            m_tree->setCurrentItem(item);
×
786

787
            redrawPreview();
×
788
        }
789
    }
790

791
    // Continue running if appropriate
792
    continueRunning(running);
×
793
}
794

795
void EFXEditor::slotLowerFixtureClicked()
×
796
{
797
    // Stop running while moving fixtures
798
    bool running = interruptRunning();
×
799

800
    QTreeWidgetItem* item = m_tree->currentItem();
×
801
    if (item != NULL)
×
802
    {
803
        int index = m_tree->indexOfTopLevelItem(item);
×
804
        if (index == (m_tree->topLevelItemCount() - 1))
×
805
            return;
806

807
        EFXFixture* ef = reinterpret_cast <EFXFixture*>
808
                         (item->data(0, Qt::UserRole).toULongLong());
×
809
        Q_ASSERT(ef != NULL);
810

811
        if (m_efx->lowerFixture(ef) == true)
×
812
        {
813
            item = m_tree->takeTopLevelItem(index);
×
814
            m_tree->insertTopLevelItem(index + 1, item);
×
815

816
            updateModeColumn(item, ef);
×
817
            updateStartOffsetColumn(item, ef);
×
818
            updateIndices(index, index + 1);
×
819
            m_tree->setCurrentItem(item);
×
820

821
            redrawPreview();
×
822
        }
823
    }
824

825
    // Continue running if appropriate
826
    continueRunning(running);
×
827
}
828

829
void EFXEditor::slotParallelRadioToggled(bool state)
×
830
{
831
    Q_ASSERT(m_efx != NULL);
832
    if (state == true)
×
833
        m_efx->setPropagationMode(EFX::Parallel);
×
834
}
×
835

836
void EFXEditor::slotSerialRadioToggled(bool state)
×
837
{
838
    Q_ASSERT(m_efx != NULL);
839
    if (state == true)
×
840
        m_efx->setPropagationMode(EFX::Serial);
×
841
}
×
842

843
void EFXEditor::slotAsymmetricRadioToggled(bool state)
×
844
{
845
    Q_ASSERT(m_efx != NULL);
846
    if (state == true)
×
847
        m_efx->setPropagationMode(EFX::Asymmetric);
×
848
}
×
849

850
void EFXEditor::slotFadeInChanged(int ms)
×
851
{
852
    m_efx->setFadeInSpeed(ms);
×
853
    slotRestartTest();
×
854
}
×
855

856
void EFXEditor::slotFadeOutChanged(int ms)
×
857
{
858
    m_efx->setFadeOutSpeed(ms);
×
859
}
×
860

861
void EFXEditor::slotHoldChanged(int ms)
×
862
{
863
    uint duration = 0;
864
    if (ms < 0)
×
865
        duration = ms;
×
866
    else
867
        duration = m_efx->fadeInSpeed() + ms + m_efx->fadeOutSpeed();
×
868
    m_efx->setDuration(duration);
×
869
    redrawPreview();
×
870
}
×
871

872
void EFXEditor::slotFixtureRemoved()
×
873
{
874
    // EFX already catches fixture removals so just update the list
875
    updateFixtureTree();
×
876
    redrawPreview();
×
877
}
×
878

879
void EFXEditor::slotFixtureChanged()
×
880
{
881
    // Update the tree in case fixture's name changes
882
    updateFixtureTree();
×
883
}
×
884

885
/*****************************************************************************
886
 * Movement page
887
 *****************************************************************************/
888

889
void EFXEditor::slotAlgorithmSelected(int algoIndex)
×
890
{
891
    Q_ASSERT(m_efx != NULL);
892

893
    m_efx->setAlgorithm(EFX::Algorithm(algoIndex));
×
894

895
    if (m_efx->isFrequencyEnabled())
×
896
    {
897
        m_xFrequencyLabel->setEnabled(true);
×
898
        m_yFrequencyLabel->setEnabled(true);
×
899

900
        m_xFrequencySpin->setEnabled(true);
×
901
        m_yFrequencySpin->setEnabled(true);
×
902
    }
903
    else
904
    {
905
        m_xFrequencyLabel->setEnabled(false);
×
906
        m_yFrequencyLabel->setEnabled(false);
×
907

908
        m_xFrequencySpin->setEnabled(false);
×
909
        m_yFrequencySpin->setEnabled(false);
×
910
    }
911

912
    if (m_efx->isPhaseEnabled())
×
913
    {
914
        m_xPhaseLabel->setEnabled(true);
×
915
        m_yPhaseLabel->setEnabled(true);
×
916

917
        m_xPhaseSpin->setEnabled(true);
×
918
        m_yPhaseSpin->setEnabled(true);
×
919
    }
920
    else
921
    {
922
        m_xPhaseLabel->setEnabled(false);
×
923
        m_yPhaseLabel->setEnabled(false);
×
924

925
        m_xPhaseSpin->setEnabled(false);
×
926
        m_yPhaseSpin->setEnabled(false);
×
927
    }
928

929
    redrawPreview();
×
930
}
×
931

932
void EFXEditor::slotWidthSpinChanged(int value)
×
933
{
934
    Q_ASSERT(m_efx != NULL);
935
    m_efx->setWidth(value);
×
936
    redrawPreview();
×
937
}
×
938

939
void EFXEditor::slotHeightSpinChanged(int value)
×
940
{
941
    Q_ASSERT(m_efx != NULL);
942
    m_efx->setHeight(value);
×
943
    redrawPreview();
×
944
}
×
945

946
void EFXEditor::slotRotationSpinChanged(int value)
×
947
{
948
    Q_ASSERT(m_efx != NULL);
949
    m_efx->setRotation(value);
×
950
    redrawPreview();
×
951
}
×
952

953
void EFXEditor::slotStartOffsetSpinChanged(int value)
×
954
{
955
    Q_ASSERT(m_efx != NULL);
956
    m_efx->setStartOffset(value);
×
957
    redrawPreview();
×
958
}
×
959

960
void EFXEditor::slotIsRelativeCheckboxChanged(int value)
×
961
{
962
    Q_ASSERT(m_efx != NULL);
963
    m_efx->setIsRelative(value == Qt::Checked);
×
964
}
×
965

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

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

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

987
void EFXEditor::slotYFrequencySpinChanged(int value)
×
988
{
989
    Q_ASSERT(m_efx != NULL);
990
    m_efx->setYFrequency(value);
×
991
    redrawPreview();
×
992
}
×
993

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

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

1008
/*****************************************************************************
1009
 * Run order
1010
 *****************************************************************************/
1011

1012
void EFXEditor::slotLoopClicked()
×
1013
{
1014
    Q_ASSERT(m_efx != NULL);
1015
    m_efx->setRunOrder(Function::Loop);
×
1016
}
×
1017

1018
void EFXEditor::slotSingleShotClicked()
×
1019
{
1020
    Q_ASSERT(m_efx != NULL);
1021
    m_efx->setRunOrder(Function::SingleShot);
×
1022
}
×
1023

1024
void EFXEditor::slotPingPongClicked()
×
1025
{
1026
    Q_ASSERT(m_efx != NULL);
1027
    m_efx->setRunOrder(Function::PingPong);
×
1028
}
×
1029

1030
/*****************************************************************************
1031
 * Direction
1032
 *****************************************************************************/
1033

1034
void EFXEditor::slotForwardClicked()
×
1035
{
1036
    Q_ASSERT(m_efx != NULL);
1037
    m_efx->setDirection(Function::Forward);
×
1038
    redrawPreview();
×
1039
}
×
1040

1041
void EFXEditor::slotBackwardClicked()
×
1042
{
1043
    Q_ASSERT(m_efx != NULL);
1044
    m_efx->setDirection(Function::Backward);
×
1045
    redrawPreview();
×
1046
}
×
1047

1048
void EFXEditor::redrawPreview()
×
1049
{
1050
    if (m_previewArea == NULL)
×
1051
        return;
×
1052

1053
    QPolygonF polygon;
1054
    m_efx->preview(polygon);
×
1055

1056
    QVector <QPolygonF> fixturePoints;
1057
    m_efx->previewFixtures(fixturePoints);
×
1058

1059
    m_previewArea->setPolygon(polygon);
×
1060
    m_previewArea->setFixturePolygons(fixturePoints);
×
1061

1062
    m_previewArea->draw(m_efx->duration() / polygon.size());
×
1063
}
×
1064

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

© 2025 Coveralls, Inc