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

mcallegari / qlcplus / 6683238402

29 Oct 2023 12:10PM UTC coverage: 28.07%. Remained the same
6683238402

push

github

mcallegari
engine: fix build

15385 of 54809 relevant lines covered (28.07%)

20267.63 hits per line

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

76.92
/engine/src/scene.cpp
1
/*
2
  Q Light Controller Plus
3
  scene.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

21
#include <QXmlStreamReader>
22
#include <QXmlStreamWriter>
23
#include <QDebug>
24
#include <QList>
25
#include <QFile>
26

27
#include "qlcfixturedef.h"
28
#include "qlccapability.h"
29

30
#include "genericfader.h"
31
#include "mastertimer.h"
32
#include "universe.h"
33
#include "scene.h"
34
#include "doc.h"
35
#include "bus.h"
36

37
/*****************************************************************************
38
 * Initialization
39
 *****************************************************************************/
40

41
Scene::Scene(Doc* doc)
205✔
42
    : Function(doc, Function::SceneType)
43
    , m_legacyFadeBus(Bus::invalid())
410✔
44
    , m_blendFunctionID(Function::invalidId())
205✔
45
{
46
    setName(tr("New Scene"));
205✔
47
    registerAttribute(tr("ParentIntensity"), Multiply | Single);
205✔
48
}
205✔
49

50
Scene::~Scene()
396✔
51
{
52
}
396✔
53

54
QIcon Scene::getIcon() const
×
55
{
56
    return QIcon(":/scene.png");
×
57
}
58

59
quint32 Scene::totalDuration()
2✔
60
{
61
    return (quint32)duration();
2✔
62
}
63

64
/*****************************************************************************
65
 * Copying
66
 *****************************************************************************/
67

68
Function* Scene::createCopy(Doc* doc, bool addToDoc)
1✔
69
{
70
    Q_ASSERT(doc != NULL);
1✔
71

72
    Function* copy = new Scene(doc);
1✔
73
    if (copy->copyFrom(this) == false)
1✔
74
    {
75
        delete copy;
×
76
        copy = NULL;
×
77
    }
78
    if (addToDoc == true && doc->addFunction(copy) == false)
1✔
79
    {
80
        delete copy;
×
81
        copy = NULL;
×
82
    }
83

84
    return copy;
1✔
85
}
86

87
bool Scene::copyFrom(const Function* function)
4✔
88
{
89
    const Scene* scene = qobject_cast<const Scene*> (function);
4✔
90
    if (scene == NULL)
4✔
91
        return false;
1✔
92

93
    m_values.clear();
3✔
94
    m_values = scene->m_values;
3✔
95
    m_fixtures.clear();
3✔
96
    m_fixtures = scene->m_fixtures;
3✔
97
    m_channelGroups.clear();
3✔
98
    m_channelGroups = scene->m_channelGroups;
3✔
99
    m_channelGroupsLevels.clear();
3✔
100
    m_channelGroupsLevels = scene->m_channelGroupsLevels;
3✔
101
    m_fixtureGroups.clear();
3✔
102
    m_fixtureGroups = scene->m_fixtureGroups;
3✔
103
    m_palettes.clear();
3✔
104
    m_palettes = scene->m_palettes;
3✔
105

106
    return Function::copyFrom(function);
3✔
107
}
108

109
/*****************************************************************************
110
 * Values
111
 *****************************************************************************/
112

113
void Scene::setValue(const SceneValue& scv, bool blind, bool checkHTP)
554✔
114
{
115
    bool valChanged = false;
554✔
116

117
    if (!m_fixtures.contains(scv.fxi))
554✔
118
    {
119
        qWarning() << Q_FUNC_INFO << "Setting value for unknown fixture" << scv.fxi << ". Adding it.";
200✔
120
        m_fixtures.append(scv.fxi);
200✔
121
    }
122

123
    {
124
        QMutexLocker locker(&m_valueListMutex);
1,108✔
125

126
        QMap<SceneValue, uchar>::iterator it = m_values.find(scv);
554✔
127
        if (it == m_values.end())
554✔
128
        {
129
            m_values.insert(scv, scv.value);
551✔
130
            valChanged = true;
551✔
131
        }
132
        else if (it.value() != scv.value)
3✔
133
        {
134
            const_cast<uchar&>(it.key().value) = scv.value;
3✔
135
            it.value() = scv.value;
3✔
136
            valChanged = true;
3✔
137
        }
138

139
        // if the scene is running, we must
140
        // update/add the changed channel
141
        if (blind == false && m_fadersMap.isEmpty() == false)
554✔
142
        {
143
            Fixture *fixture = doc()->fixture(scv.fxi);
2✔
144
            if (fixture != NULL)
2✔
145
            {
146
                quint32 universe = fixture->universe();
2✔
147

148
                FadeChannel fc(doc(), scv.fxi, scv.channel);
4✔
149
                fc.setStart(scv.value);
2✔
150
                fc.setTarget(scv.value);
2✔
151
                fc.setCurrent(scv.value);
2✔
152
                fc.setFadeTime(0);
2✔
153

154
                if (m_fadersMap.contains(universe))
2✔
155
                {
156
                    if (checkHTP == false)
2✔
157
                        m_fadersMap[universe]->replace(fc);
1✔
158
                    else
159
                        m_fadersMap[universe]->add(fc);
1✔
160
                }
161
            }
162
         }
163
    }
164

165
    emit changed(this->id());
554✔
166
    if (valChanged)
554✔
167
        emit valueChanged(scv);
554✔
168
}
554✔
169

170
void Scene::setValue(quint32 fxi, quint32 ch, uchar value)
545✔
171
{
172
    setValue(SceneValue(fxi, ch, value));
545✔
173
}
545✔
174

175
void Scene::unsetValue(quint32 fxi, quint32 ch)
5✔
176
{
177
    if (!m_fixtures.contains(fxi))
5✔
178
        qWarning() << Q_FUNC_INFO << "Unsetting value for unknown fixture" << fxi;
1✔
179

180
    {
181
        QMutexLocker locker(&m_valueListMutex);
5✔
182
        m_values.remove(SceneValue(fxi, ch, 0));
5✔
183
    }
184

185
    emit changed(this->id());
5✔
186
}
5✔
187

188
uchar Scene::value(quint32 fxi, quint32 ch)
419✔
189
{
190
    return m_values.value(SceneValue(fxi, ch, 0), 0);
419✔
191
}
192

193
bool Scene::checkValue(SceneValue val)
407✔
194
{
195
    return m_values.contains(val);
407✔
196
}
197

198
QList <SceneValue> Scene::values() const
222✔
199
{
200
    return m_values.keys();
222✔
201
}
202

203
QList<quint32> Scene::components()
1✔
204
{
205
    QList<quint32> ids;
1✔
206

207
    foreach(SceneValue scv, m_values.keys())
10✔
208
    {
209
        if (ids.contains(scv.fxi) == false)
4✔
210
            ids.append(scv.fxi);
3✔
211
    }
212

213
    return ids;
1✔
214
}
215

216
QColor Scene::colorValue(quint32 fxi)
3✔
217
{
218
    int rVal = 0, gVal = 0, bVal = 0;
3✔
219
    int cVal = -1, mVal = -1, yVal = -1;
3✔
220
    bool found = false;
3✔
221
    QColor CMYcol;
3✔
222

223
    foreach(SceneValue scv, m_values.keys())
54✔
224
    {
225
        if (fxi != Fixture::invalidId() && fxi != scv.fxi)
24✔
226
            continue;
16✔
227

228
        Fixture *fixture = doc()->fixture(scv.fxi);
8✔
229
        if (fixture == NULL)
8✔
230
            continue;
×
231

232
        const QLCChannel* channel = fixture->channel(scv.channel);
8✔
233
        if (channel == NULL)
8✔
234
            continue;
×
235

236
        if (channel->group() == QLCChannel::Intensity)
8✔
237
        {
238
            QLCChannel::PrimaryColour col = channel->colour();
7✔
239
            switch (col)
7✔
240
            {
241
                case QLCChannel::Red: rVal = scv.value; found = true; break;
1✔
242
                case QLCChannel::Green: gVal = scv.value; found = true; break;
1✔
243
                case QLCChannel::Blue: bVal = scv.value; found = true; break;
1✔
244
                case QLCChannel::Cyan: cVal = scv.value; break;
1✔
245
                case QLCChannel::Magenta: mVal = scv.value; break;
1✔
246
                case QLCChannel::Yellow: yVal = scv.value; break;
1✔
247
                case QLCChannel::White: rVal = gVal = bVal = scv.value; found = true; break;
×
248
                default: break;
1✔
249
            }
250
        }
251
        else if (channel->group() == QLCChannel::Colour)
1✔
252
        {
253
            QLCCapability *cap = channel->searchCapability(scv.value);
1✔
254
            if (cap &&
2✔
255
                (cap->presetType() == QLCCapability::SingleColor ||
1✔
256
                 cap->presetType() == QLCCapability::DoubleColor))
×
257
            {
258
                QColor col = cap->resource(0).value<QColor>();
1✔
259
                rVal = col.red();
1✔
260
                gVal = col.green();
1✔
261
                bVal = col.blue();
1✔
262
                found = true;
1✔
263
            }
264
        }
265

266
        if (cVal >= 0 && mVal >= 0 && yVal >= 0)
8✔
267
        {
268
            CMYcol.setCmyk(cVal, mVal, yVal, 0);
1✔
269
            rVal = CMYcol.red();
1✔
270
            gVal = CMYcol.green();
1✔
271
            bVal = CMYcol.blue();
1✔
272
            found = true;
1✔
273
        }
274
    }
275

276
    if (found)
3✔
277
        return QColor(rVal, gVal, bVal);
3✔
278

279
    return QColor();
×
280
}
281

282
void Scene::clear()
1✔
283
{
284
    m_values.clear();
1✔
285
    m_fixtures.clear();
1✔
286
    m_fixtureGroups.clear();
1✔
287
    m_palettes.clear();
1✔
288
}
1✔
289

290
/*********************************************************************
291
 * Channel Groups
292
 *********************************************************************/
293

294
void Scene::addChannelGroup(quint32 id)
2✔
295
{
296
    if (m_channelGroups.contains(id) == false)
2✔
297
    {
298
        m_channelGroups.append(id);
1✔
299
        m_channelGroupsLevels.append(0);
1✔
300
    }
301
}
2✔
302

303
void Scene::removeChannelGroup(quint32 id)
2✔
304
{
305
    int idx = m_channelGroups.indexOf(id);
2✔
306
    if (idx != -1)
2✔
307
    {
308
        m_channelGroups.removeAt(idx);
1✔
309
        m_channelGroupsLevels.removeAt(idx);
1✔
310
    }
311
}
2✔
312

313
void Scene::setChannelGroupLevel(quint32 id, uchar level)
1✔
314
{
315
    int idx = m_channelGroups.indexOf(id);
1✔
316
    if (idx >= 0 && idx < m_channelGroupsLevels.count())
1✔
317
        m_channelGroupsLevels[idx] = level;
1✔
318
}
1✔
319

320
QList<uchar> Scene::channelGroupsLevels()
6✔
321
{
322
    return m_channelGroupsLevels;
6✔
323
}
324

325
QList<quint32> Scene::channelGroups()
6✔
326
{
327
    return m_channelGroups;
6✔
328
}
329

330
/*****************************************************************************
331
 * Fixtures
332
 *****************************************************************************/
333

334
void Scene::slotFixtureRemoved(quint32 fxi_id)
4✔
335
{
336
    bool hasChanged = false;
4✔
337

338
    QMutableMapIterator <SceneValue, uchar> it(m_values);
4✔
339
    while (it.hasNext() == true)
10✔
340
    {
341
        SceneValue value(it.next().key());
12✔
342
        if (value.fxi == fxi_id)
6✔
343
        {
344
            it.remove();
2✔
345
            hasChanged = true;
2✔
346
        }
347
    }
348

349
    if (removeFixture(fxi_id))
4✔
350
        hasChanged = true;
2✔
351

352
    if (hasChanged)
4✔
353
        emit changed(this->id());
2✔
354
}
4✔
355

356
void Scene::addFixture(quint32 fixtureId)
7✔
357
{
358
    if (m_fixtures.contains(fixtureId) == false)
7✔
359
        m_fixtures.append(fixtureId);
7✔
360
}
7✔
361

362
bool Scene::removeFixture(quint32 fixtureId)
4✔
363
{
364
    return m_fixtures.removeOne(fixtureId);
4✔
365
}
366

367
QList<quint32> Scene::fixtures() const
2✔
368
{
369
    return m_fixtures;
2✔
370
}
371

372
/*********************************************************************
373
 * Fixture Groups
374
 *********************************************************************/
375

376
void Scene::addFixtureGroup(quint32 id)
×
377
{
378
    if (m_fixtureGroups.contains(id) == false)
×
379
        m_fixtureGroups.append(id);
×
380
}
×
381

382
bool Scene::removeFixtureGroup(quint32 id)
×
383
{
384
    return m_fixtureGroups.removeOne(id);
×
385
}
386

387
QList<quint32> Scene::fixtureGroups() const
×
388
{
389
    return m_fixtureGroups;
×
390
}
391

392
/*********************************************************************
393
 * Palettes
394
 *********************************************************************/
395

396
void Scene::addPalette(quint32 id)
×
397
{
398
    if (m_palettes.contains(id) == false)
×
399
        m_palettes.append(id);
×
400
}
×
401

402
bool Scene::removePalette(quint32 id)
×
403
{
404
    return m_palettes.removeOne(id);
×
405
}
406

407
QList<quint32> Scene::palettes() const
119✔
408
{
409
    return m_palettes;
119✔
410
}
411

412
/*****************************************************************************
413
 * Load & Save
414
 *****************************************************************************/
415

416
bool Scene::saveXML(QXmlStreamWriter *doc)
2✔
417
{
418
    Q_ASSERT(doc != NULL);
2✔
419

420
    /* Function tag */
421
    doc->writeStartElement(KXMLQLCFunction);
2✔
422

423
    /* Common attributes */
424
    saveXMLCommon(doc);
2✔
425

426
    /* Speed */
427
    saveXMLSpeed(doc);
2✔
428

429
    /* Channel groups */
430
    if (m_channelGroups.count() > 0)
2✔
431
    {
432
        QString chanGroupsIDs;
×
433
        for (int i = 0; i < m_channelGroups.size(); ++i)
×
434
        {
435
            if (chanGroupsIDs.isEmpty() == false)
×
436
                chanGroupsIDs.append(QString(","));
×
437
            int id = m_channelGroups.at(i);
×
438
            int val = m_channelGroupsLevels.at(i);
×
439
            chanGroupsIDs.append(QString("%1,%2").arg(id).arg(val));
×
440
        }
441
        doc->writeTextElement(KXMLQLCSceneChannelGroupsValues, chanGroupsIDs);
×
442
    }
443

444
    /* Scene contents */
445
    // make a copy of the Scene values cause we need to empty it in the process
446
    QList<SceneValue> values = m_values.keys();
2✔
447

448
    // loop through the Scene Fixtures in the order they've been added
449
    foreach (quint32 fxId, m_fixtures)
6✔
450
    {
451
        QStringList currFixValues;
4✔
452
        bool found = false;
2✔
453

454
        // look for the values that match the current Fixture ID
455
        for (int j = 0; j < values.count(); j++)
6✔
456
        {
457
            SceneValue scv = values.at(j);
5✔
458
            if (scv.fxi != fxId)
5✔
459
            {
460
                if (found == true)
1✔
461
                    break;
1✔
462
                else
463
                    continue;
×
464
            }
465

466
            found = true;
4✔
467
            currFixValues.append(QString::number(scv.channel));
4✔
468
            // IMPORTANT: if a Scene is hidden, so used as a container by some Sequences,
469
            // it must be saved with values set to zero
470
            currFixValues.append(QString::number(isVisible() ? scv.value : 0));
4✔
471
            values.removeAt(j);
4✔
472
            j--;
4✔
473
        }
474

475
        saveXMLFixtureValues(doc, fxId, currFixValues);
2✔
476
    }
477

478
    /* Save referenced Fixture Groups */
479
    foreach (quint32 groupId, m_fixtureGroups)
2✔
480
    {
481
        doc->writeStartElement(KXMLQLCFixtureGroup);
×
482
        doc->writeAttribute(KXMLQLCFixtureGroupID, QString::number(groupId));
×
483
        doc->writeEndElement();
×
484
    }
485

486
    /* Save referenced Palettes */
487
    foreach (quint32 pId, m_palettes)
2✔
488
    {
489
        doc->writeStartElement(KXMLQLCPalette);
×
490
        doc->writeAttribute(KXMLQLCPaletteID, QString::number(pId));
×
491
        doc->writeEndElement();
×
492
    }
493

494
    /* End the <Function> tag */
495
    doc->writeEndElement();
2✔
496

497
    return true;
4✔
498
}
499

500
bool Scene::saveXMLFixtureValues(QXmlStreamWriter* doc, quint32 fixtureID, QStringList const& values)
2✔
501
{
502
    doc->writeStartElement(KXMLQLCFixtureValues);
2✔
503
    doc->writeAttribute(KXMLQLCFixtureID, QString::number(fixtureID));
2✔
504
    if (values.size() > 0)
2✔
505
        doc->writeCharacters(values.join(","));
2✔
506
    doc->writeEndElement();
2✔
507
    return true;
2✔
508
}
509

510
bool Scene::loadXML(QXmlStreamReader &root)
4✔
511
{
512
    if (root.name() != KXMLQLCFunction)
4✔
513
    {
514
        qWarning() << Q_FUNC_INFO << "Function node not found";
1✔
515
        return false;
1✔
516
    }
517

518
    if (root.attributes().value(KXMLQLCFunctionType).toString() != typeToString(Function::SceneType))
3✔
519
    {
520
        qWarning() << Q_FUNC_INFO << "Function is not a scene";
1✔
521
        return false;
1✔
522
    }
523

524
    /* Load scene contents */
525
    while (root.readNextStartElement())
9✔
526
    {
527
        if (root.name() == KXMLQLCBus)
7✔
528
        {
529
            m_legacyFadeBus = root.readElementText().toUInt();
2✔
530
        }
531
        else if (root.name() == KXMLQLCFunctionSpeed)
5✔
532
        {
533
            loadXMLSpeed(root);
1✔
534
        }
535
        else if (root.name() == KXMLQLCSceneChannelGroups)
4✔
536
        {
537
            QString chGrpIDs = root.readElementText();
×
538
            if (chGrpIDs.isEmpty() == false)
×
539
            {
540
                QStringList grpArray = chGrpIDs.split(",");
×
541
                foreach(QString grp, grpArray)
×
542
                {
543
                    m_channelGroups.append(grp.toUInt());
×
544
                    m_channelGroupsLevels.append(0);
×
545
                }
546
            }
547
        }
548
        else if (root.name() == KXMLQLCSceneChannelGroupsValues)
4✔
549
        {
550
            QString chGrpIDs = root.readElementText();
×
551
            if (chGrpIDs.isEmpty() == false)
×
552
            {
553
                QStringList grpArray = chGrpIDs.split(",");
×
554
                for (int i = 0; i + 1 < grpArray.count(); i+=2)
×
555
                {
556
                    m_channelGroups.append(grpArray.at(i).toUInt());
×
557
                    m_channelGroupsLevels.append(grpArray.at(i + 1).toUInt());
×
558
                }
559
            }
560
        }
561
        /* "old" style XML */
562
        else if (root.name() == KXMLQLCFunctionValue)
4✔
563
        {
564
            /* Channel value */
565
            SceneValue scv;
6✔
566
            if (scv.loadXML(root) == true)
3✔
567
                setValue(scv);
3✔
568
        }
569
        /* "new" style XML */
570
        else if (root.name() == KXMLQLCFixtureValues)
1✔
571
        {
572
            quint32 fxi = root.attributes().value(KXMLQLCFixtureID).toString().toUInt();
×
573
            addFixture(fxi);
×
574
            QString strvals = root.readElementText();
×
575
            if (strvals.isEmpty() == false)
×
576
            {
577
                QStringList varray = strvals.split(",");
×
578
                for (int i = 0; i + 1 < varray.count(); i+=2)
×
579
                {
580
                    SceneValue scv;
×
581
                    scv.fxi = fxi;
×
582
                    scv.channel = QString(varray.at(i)).toUInt();
×
583
                    scv.value = uchar(QString(varray.at(i + 1)).toInt());
×
584
                    setValue(scv);
×
585
                }
586
            }
587
        }
588
        else if (root.name() == KXMLQLCFixtureGroup)
1✔
589
        {
590
            quint32 id = root.attributes().value(KXMLQLCFixtureGroupID).toString().toUInt();
×
591
            addFixtureGroup(id);
×
592
            root.skipCurrentElement();
×
593
        }
594
        else if (root.name() == KXMLQLCPalette)
1✔
595
        {
596
            quint32 id = root.attributes().value(KXMLQLCPaletteID).toString().toUInt();
×
597
            addPalette(id);
×
598
            root.skipCurrentElement();
×
599
        }
600
        else
601
        {
602
            qWarning() << Q_FUNC_INFO << "Unknown scene tag:" << root.name();
1✔
603
            root.skipCurrentElement();
1✔
604
        }
605
    }
606

607
    return true;
2✔
608
}
609

610
void Scene::postLoad()
×
611
{
612
    // Map legacy bus speed to fixed speed values
613
    if (m_legacyFadeBus != Bus::invalid())
×
614
    {
615
        quint32 value = Bus::instance()->value(m_legacyFadeBus);
×
616
        setFadeInSpeed((value / MasterTimer::frequency()) * 1000);
×
617
        setFadeOutSpeed((value / MasterTimer::frequency()) * 1000);
×
618
    }
619

620
    // Remove such fixtures and channels that don't exist
621
    QMutableMapIterator <SceneValue, uchar> it(m_values);
×
622
    while (it.hasNext() == true)
×
623
    {
624
        SceneValue value(it.next().key());
×
625
        Fixture* fxi = doc()->fixture(value.fxi);
×
626
        if (fxi == NULL || fxi->channel(value.channel) == NULL)
×
627
            it.remove();
×
628
    }
629
}
×
630

631
/****************************************************************************
632
 * Flashing
633
 ****************************************************************************/
634

635
void Scene::flash(MasterTimer *timer)
6✔
636
{
637
    if (flashing() == true)
6✔
638
        return;
1✔
639

640
    Q_ASSERT(timer != NULL);
5✔
641
    Function::flash(timer);
5✔
642
    timer->registerDMXSource(this);
5✔
643
}
644

645
void Scene::unFlash(MasterTimer *timer)
5✔
646
{
647
    if (flashing() == false)
5✔
648
        return;
×
649

650
    Q_ASSERT(timer != NULL);
5✔
651
    Function::unFlash(timer);
5✔
652
}
653

654
void Scene::writeDMX(MasterTimer *timer, QList<Universe *> ua)
5✔
655
{
656
    Q_ASSERT(timer != NULL);
5✔
657

658
    if (flashing() == true)
5✔
659
    {
660
        if (m_fadersMap.isEmpty())
2✔
661
        {
662
            // Keep HTP and LTP channels up. Flash is more or less a forceful intervention
663
            // so enforce all values that the user has chosen to flash.
664
            foreach (const SceneValue& sv, m_values.keys())
8✔
665
            {
666
                FadeChannel fc(doc(), sv.fxi, sv.channel);
3✔
667
                quint32 universe = fc.universe();
3✔
668
                if (universe == Universe::invalid())
3✔
669
                    continue;
×
670

671
                QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
6✔
672
                if (fader.isNull())
3✔
673
                {
674
                    fader = ua[universe]->requestFader();
1✔
675
                    fader->adjustIntensity(getAttributeValue(Intensity));
1✔
676
                    fader->setBlendMode(blendMode());
1✔
677
                    fader->setName(name());
1✔
678
                    fader->setParentFunctionID(id());
1✔
679
                    m_fadersMap[universe] = fader;
1✔
680
                }
681

682
                fc.setTarget(sv.value);
3✔
683
                fc.addFlag(FadeChannel::Flashing);
3✔
684
                fader->add(fc);
3✔
685
            }
686
        }
687
    }
688
    else
689
    {
690
        handleFadersEnd(timer);
3✔
691
        timer->unregisterDMXSource(this);
3✔
692
    }
693
}
5✔
694

695
/****************************************************************************
696
 * Running
697
 ****************************************************************************/
698

699
void Scene::processValue(MasterTimer *timer, QList<Universe*> ua, uint fadeIn, SceneValue &scv)
512✔
700
{
701
    Fixture *fixture = doc()->fixture(scv.fxi);
512✔
702

703
    if (fixture == NULL)
512✔
704
        return;
×
705

706
    quint32 universe = fixture->universe();
512✔
707
    if (universe == Universe::invalid())
512✔
708
        return;
×
709

710
    QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
1,024✔
711
    if (fader.isNull())
512✔
712
    {
713
        fader = ua[universe]->requestFader();
119✔
714
        fader->adjustIntensity(getAttributeValue(Intensity));
119✔
715
        fader->setBlendMode(blendMode());
119✔
716
        fader->setName(name());
119✔
717
        fader->setParentFunctionID(id());
119✔
718
        m_fadersMap[universe] = fader;
119✔
719

720
        fader->setParentIntensity(getAttributeValue(ParentIntensity));
119✔
721
    }
722

723
    FadeChannel *fc = fader->getChannelFader(doc(), ua[universe], scv.fxi, scv.channel);
512✔
724

725
    /** If a blend Function has been set, check if this channel needs to
726
     *  be blended from a previous value. If so, mark it for crossfade
727
     *  and set its current value */
728
    if (blendFunctionID() != Function::invalidId())
512✔
729
    {
730
        Scene *blendScene = qobject_cast<Scene *>(doc()->function(blendFunctionID()));
405✔
731
        if (blendScene != NULL && blendScene->checkValue(scv))
405✔
732
        {
733
            fc->addFlag(FadeChannel::CrossFade);
405✔
734
            fc->setCurrent(blendScene->value(scv.fxi, scv.channel));
405✔
735
            qDebug() << "----- BLEND from Scene" << blendScene->name()
810✔
736
                     << ", fixture:" << scv.fxi << ", channel:" << scv.channel << ", value:" << fc->current();
405✔
737
        }
738
    }
739
    else
740
    {
741
        qDebug() << "Scene" << name() << "add channel" << scv.channel << "from" << fc->current() << "to" << scv.value;
107✔
742
    }
743

744
    fc->setStart(fc->current());
512✔
745
    fc->setTarget(scv.value);
512✔
746

747
    if (fc->canFade() == false)
512✔
748
    {
749
        fc->setFadeTime(0);
×
750
    }
751
    else
752
    {
753
        if (tempoType() == Beats)
512✔
754
        {
755
            int fadeInTime = beatsToTime(fadeIn, timer->beatTimeDuration());
×
756
            int beatOffset = timer->nextBeatTimeOffset();
×
757

758
            if (fadeInTime - beatOffset > 0)
×
759
                fc->setFadeTime(fadeInTime - beatOffset);
×
760
            else
761
                fc->setFadeTime(fadeInTime);
×
762
        }
763
        else
764
        {
765
            fc->setFadeTime(fadeIn);
512✔
766
        }
767
    }
768
}
769

770
void Scene::handleFadersEnd(MasterTimer *timer)
109✔
771
{
772
    uint fadeout = overrideFadeOutSpeed() == defaultSpeed() ? fadeOutSpeed() : overrideFadeOutSpeed();
109✔
773

774
    /* If no fade out is needed, dismiss all the requested faders.
775
     * Otherwise, set all the faders to fade out and let Universe dismiss them
776
     * when done */
777
    if (fadeout == 0)
109✔
778
    {
779
        dismissAllFaders();
104✔
780
    }
781
    else
782
    {
783
        if (tempoType() == Beats)
5✔
784
            fadeout = beatsToTime(fadeout, timer->beatTimeDuration());
×
785

786
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
18✔
787
        {
788
            if (!fader.isNull())
4✔
789
                fader->setFadeOut(true, fadeout);
4✔
790
        }
791
    }
792

793
    m_fadersMap.clear();
109✔
794

795
    // autonomously reset a blend function if set
796
    setBlendFunctionID(Function::invalidId());
109✔
797
}
109✔
798

799
void Scene::write(MasterTimer *timer, QList<Universe*> ua)
372✔
800
{
801
    //qDebug() << Q_FUNC_INFO << elapsed();
802

803
    if (m_values.count() == 0 && m_palettes.count() == 0)
372✔
804
    {
805
        stop(FunctionParent::master());
1✔
806
        return;
1✔
807
    }
808

809
    if (m_fadersMap.isEmpty())
371✔
810
    {
811
        uint fadeIn = overrideFadeInSpeed() == defaultSpeed() ? fadeInSpeed() : overrideFadeInSpeed();
119✔
812

813
        foreach (quint32 paletteID, palettes())
238✔
814
        {
815
            QLCPalette *palette = doc()->palette(paletteID);
×
816
            if (palette == NULL)
×
817
                continue;
×
818

819
            foreach (SceneValue scv, palette->valuesFromFixtureGroups(doc(), fixtureGroups()))
×
820
                processValue(timer, ua, fadeIn, scv);
×
821

822
            foreach (SceneValue scv, palette->valuesFromFixtures(doc(), fixtures()))
×
823
                processValue(timer, ua, fadeIn, scv);
×
824
        }
825

826
        QMutexLocker locker(&m_valueListMutex);
238✔
827
        QMapIterator <SceneValue, uchar> it(m_values);
238✔
828
        while (it.hasNext() == true)
631✔
829
        {
830
            SceneValue scv(it.next().key());
512✔
831
            processValue(timer, ua, fadeIn, scv);
512✔
832
        }
833
    }
834

835
    if (isPaused() == false)
371✔
836
    {
837
        incrementElapsed();
368✔
838
        if (timer->isBeat() && tempoType() == Beats)
368✔
839
            incrementElapsedBeats();
×
840
    }
841
}
842

843
void Scene::postRun(MasterTimer* timer, QList<Universe *> ua)
106✔
844
{
845
    handleFadersEnd(timer);
106✔
846

847
    Function::postRun(timer, ua);
106✔
848
}
106✔
849

850
void Scene::setPause(bool enable)
6✔
851
{
852
    if (!isRunning())
6✔
853
        return;
×
854

855
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
16✔
856
    {
857
        if (!fader.isNull())
2✔
858
            fader->setPaused(enable);
2✔
859
    }
860
    Function::setPause(enable);
6✔
861
}
862

863
/****************************************************************************
864
 * Intensity
865
 ****************************************************************************/
866

867
int Scene::adjustAttribute(qreal fraction, int attributeId)
242✔
868
{
869
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
242✔
870

871
    if (attrIndex == Intensity)
242✔
872
    {
873
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
252✔
874
        {
875
            if (!fader.isNull())
2✔
876
                fader->adjustIntensity(getAttributeValue(Function::Intensity));
2✔
877
        }
878
    }
879
    else if (attrIndex == ParentIntensity)
118✔
880
    {
881
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
230✔
882
        {
883
            if (!fader.isNull())
2✔
884
                fader->setParentIntensity(getAttributeValue(ParentIntensity));
2✔
885
        }
886
    }
887

888
    return attrIndex;
242✔
889
}
890

891
/*************************************************************************
892
 * Blend mode
893
 *************************************************************************/
894

895
void Scene::setBlendMode(Universe::BlendMode mode)
3✔
896
{
897
    if (mode == blendMode())
3✔
898
        return;
1✔
899

900
    qDebug() << "Scene" << name() << "blend mode set to" << Universe::blendModeToString(mode);
2✔
901

902
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
4✔
903
    {
904
        if (!fader.isNull())
×
905
            fader->setBlendMode(mode);
×
906
    }
907

908
    Function::setBlendMode(mode);
2✔
909
}
910

911
quint32 Scene::blendFunctionID() const
917✔
912
{
913
    return m_blendFunctionID;
917✔
914
}
915

916
void Scene::setBlendFunctionID(quint32 fid)
200✔
917
{
918
    m_blendFunctionID = fid;
200✔
919
    if (isRunning() && fid == Function::invalidId())
200✔
920
    {
921
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
214✔
922
        {
923
            if (!fader.isNull())
×
924
                fader->resetCrossfade();
×
925
        }
926
    }
927
}
200✔
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