• 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

76.19
/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 <cmath>
25
#include <QList>
26
#include <QFile>
27

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

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

38
/*****************************************************************************
39
 * Initialization
40
 *****************************************************************************/
41

42
Scene::Scene(Doc* doc)
211✔
43
    : Function(doc, Function::SceneType)
44
    , m_legacyFadeBus(Bus::invalid())
422✔
45
    , m_flashOverrides(false)
211✔
46
    , m_flashForceLTP(false)
211✔
47
    , m_blendFunctionID(Function::invalidId())
211✔
48
{
49
    setName(tr("New Scene"));
211✔
50
    registerAttribute(tr("ParentIntensity"), Multiply | Single);
211✔
51
}
211✔
52

53
Scene::~Scene()
408✔
54
{
55
}
408✔
56

57
QIcon Scene::getIcon() const
×
58
{
59
    return QIcon(":/scene.png");
×
60
}
61

62
quint32 Scene::totalDuration()
2✔
63
{
64
    return (quint32)duration();
2✔
65
}
66

67
/*****************************************************************************
68
 * Copying
69
 *****************************************************************************/
70

71
Function* Scene::createCopy(Doc* doc, bool addToDoc)
2✔
72
{
73
    Q_ASSERT(doc != NULL);
74

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

87
    return copy;
2✔
88
}
89

90
bool Scene::copyFrom(const Function* function)
5✔
91
{
92
    const Scene* scene = qobject_cast<const Scene*> (function);
93
    if (scene == NULL)
5✔
94
        return false;
95

96
    m_values.clear();
4✔
97
    m_values = scene->m_values;
4✔
98
    m_fixtures.clear();
4✔
99
    m_fixtures = scene->m_fixtures;
4✔
100
    m_channelGroups.clear();
4✔
101
    m_channelGroups = scene->m_channelGroups;
4✔
102
    m_channelGroupsLevels.clear();
4✔
103
    m_channelGroupsLevels = scene->m_channelGroupsLevels;
4✔
104
    m_fixtureGroups.clear();
4✔
105
    m_fixtureGroups = scene->m_fixtureGroups;
4✔
106
    m_palettes.clear();
4✔
107
    m_palettes = scene->m_palettes;
4✔
108

109
    return Function::copyFrom(function);
4✔
110
}
111

112
/*****************************************************************************
113
 * Values
114
 *****************************************************************************/
115

116
void Scene::setValue(const SceneValue& scv, bool blind, bool checkHTP)
556✔
117
{
118
    bool valChanged = false;
119

120
    if (!m_fixtures.contains(scv.fxi))
556✔
121
    {
122
        qWarning() << Q_FUNC_INFO << "Setting value for unknown fixture" << scv.fxi << ". Adding it.";
202✔
123
        m_fixtures.append(scv.fxi);
202✔
124
    }
125

126
    {
127
        QMutexLocker locker(&m_valueListMutex);
556✔
128

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

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

151
                FadeChannel fc(doc(), scv.fxi, scv.channel);
2✔
152
                fc.setStart(scv.value);
2✔
153
                fc.setTarget(scv.value);
2✔
154
                fc.setCurrent(scv.value);
2✔
155
                fc.setFadeTime(0);
2✔
156

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

168
    emit changed(this->id());
556✔
169
    if (valChanged)
556✔
170
        emit valueChanged(scv);
556✔
171
}
556✔
172

173
void Scene::setValue(quint32 fxi, quint32 ch, uchar value)
547✔
174
{
175
    setValue(SceneValue(fxi, ch, value));
547✔
176
}
547✔
177

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

183
    {
184
        QMutexLocker locker(&m_valueListMutex);
5✔
185
        m_values.remove(SceneValue(fxi, ch, 0));
5✔
186
    }
187

188
    emit changed(this->id());
5✔
189
}
5✔
190

191
uchar Scene::value(quint32 fxi, quint32 ch)
421✔
192
{
193
    return m_values.value(SceneValue(fxi, ch, 0), 0);
842✔
194
}
195

196
bool Scene::checkValue(SceneValue val)
409✔
197
{
198
    return m_values.contains(val);
409✔
199
}
200

201
QList <SceneValue> Scene::values() const
222✔
202
{
203
    return m_values.keys();
222✔
204
}
205

206
QList<quint32> Scene::components()
1✔
207
{
208
    QList<quint32> ids;
209

210
    foreach (SceneValue scv, m_values.keys())
6✔
211
    {
212
        if (ids.contains(scv.fxi) == false)
4✔
213
            ids.append(scv.fxi);
3✔
214
    }
4✔
215

216
    return ids;
1✔
217
}
×
218

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

226
    foreach (SceneValue scv, m_values.keys())
30✔
227
    {
228
        if (fxi != Fixture::invalidId() && fxi != scv.fxi)
24✔
229
            continue;
16✔
230

231
        Fixture *fixture = doc()->fixture(scv.fxi);
8✔
232
        if (fixture == NULL)
8✔
233
            continue;
×
234

235
        const QLCChannel* channel = fixture->channel(scv.channel);
8✔
236
        if (channel == NULL)
8✔
237
            continue;
×
238

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

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

279
    if (found)
3✔
280
        return QColor(rVal, gVal, bVal);
3✔
281

282
    return QColor();
283
}
284

285
void Scene::clear()
1✔
286
{
287
    m_values.clear();
1✔
288
    m_fixtures.clear();
1✔
289
    m_fixtureGroups.clear();
1✔
290
    m_palettes.clear();
1✔
291
}
1✔
292

293
/*********************************************************************
294
 * Channel Groups
295
 *********************************************************************/
296

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

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

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

323
QList<uchar> Scene::channelGroupsLevels()
6✔
324
{
325
    return m_channelGroupsLevels;
6✔
326
}
327

328
QList<quint32> Scene::channelGroups()
6✔
329
{
330
    return m_channelGroups;
6✔
331
}
332

333
/*****************************************************************************
334
 * Fixtures
335
 *****************************************************************************/
336

337
void Scene::slotFixtureRemoved(quint32 fxi_id)
4✔
338
{
339
    bool hasChanged = false;
340

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

352
    if (removeFixture(fxi_id))
4✔
353
        hasChanged = true;
354

355
    if (hasChanged)
2✔
356
        emit changed(this->id());
2✔
357
}
4✔
358

359
void Scene::addFixture(quint32 fixtureId)
7✔
360
{
361
    if (m_fixtures.contains(fixtureId) == false)
7✔
362
        m_fixtures.append(fixtureId);
7✔
363
}
7✔
364

365
bool Scene::removeFixture(quint32 fixtureId)
4✔
366
{
367
    return m_fixtures.removeOne(fixtureId);
4✔
368
}
369

370
QList<quint32> Scene::fixtures() const
2✔
371
{
372
    return m_fixtures;
2✔
373
}
374

375
/*********************************************************************
376
 * Fixture Groups
377
 *********************************************************************/
378

379
void Scene::addFixtureGroup(quint32 id)
×
380
{
381
    if (m_fixtureGroups.contains(id) == false)
×
382
        m_fixtureGroups.append(id);
×
383
}
×
384

385
bool Scene::removeFixtureGroup(quint32 id)
×
386
{
387
    return m_fixtureGroups.removeOne(id);
×
388
}
389

390
QList<quint32> Scene::fixtureGroups() const
×
391
{
392
    return m_fixtureGroups;
×
393
}
394

395
/*********************************************************************
396
 * Palettes
397
 *********************************************************************/
398

399
void Scene::addPalette(quint32 id)
×
400
{
401
    if (m_palettes.contains(id) == false)
×
402
        m_palettes.append(id);
×
403
}
×
404

405
bool Scene::removePalette(quint32 id)
×
406
{
407
    return m_palettes.removeOne(id);
×
408
}
409

410
QList<quint32> Scene::palettes() const
122✔
411
{
412
    return m_palettes;
122✔
413
}
414

415
/*****************************************************************************
416
 * Load & Save
417
 *****************************************************************************/
418

419
bool Scene::saveXML(QXmlStreamWriter *doc)
2✔
420
{
421
    Q_ASSERT(doc != NULL);
422

423
    /* Function tag */
424
    doc->writeStartElement(KXMLQLCFunction);
2✔
425

426
    /* Common attributes */
427
    saveXMLCommon(doc);
2✔
428

429
    /* Speed */
430
    saveXMLSpeed(doc);
2✔
431

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

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

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

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

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

478
        saveXMLFixtureValues(doc, fxId, currFixValues);
2✔
479
    }
480

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

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

497
    /* End the <Function> tag */
498
    doc->writeEndElement();
2✔
499

500
    return true;
2✔
501
}
2✔
502

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

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

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

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

610
    return true;
611
}
612

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

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

634
/****************************************************************************
635
 * Flashing
636
 ****************************************************************************/
637

638
void Scene::flash(MasterTimer *timer, bool shouldOverride, bool forceLTP)
6✔
639
{
640
    if (flashing() == true)
6✔
641
        return;
642

643
    m_flashOverrides = shouldOverride;
5✔
644
    m_flashForceLTP = forceLTP;
5✔
645

646
    Q_ASSERT(timer != NULL);
647
    Function::flash(timer, shouldOverride, forceLTP);
5✔
648
    timer->registerDMXSource(this);
5✔
649
}
650

651
void Scene::unFlash(MasterTimer *timer)
5✔
652
{
653
    if (flashing() == false)
5✔
654
        return;
655

656
    Q_ASSERT(timer != NULL);
657
    Function::unFlash(timer);
5✔
658
}
659

660
void Scene::writeDMX(MasterTimer *timer, QList<Universe *> ua)
5✔
661
{
662
    Q_ASSERT(timer != NULL);
663

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

677
                QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
6✔
678
                if (fader.isNull())
3✔
679
                {
680
                    fader = ua[universe]->requestFader(m_flashOverrides ? Universe::Flashing : Universe::Auto);
3✔
681

682
                    fader->adjustIntensity(getAttributeValue(Intensity));
1✔
683
                    fader->setBlendMode(blendMode());
1✔
684
                    fader->setName(name());
1✔
685
                    fader->setParentFunctionID(id());
1✔
686
                    m_fadersMap[universe] = fader;
1✔
687
                }
688

689
                if (m_flashForceLTP)
3✔
690
                    fc.addFlag(FadeChannel::ForceLTP);
×
691
                fc.setTarget(sv.value);
3✔
692
                fc.addFlag(FadeChannel::Flashing);
3✔
693
                fader->add(fc);
3✔
694
            }
3✔
695
        }
696
    }
697
    else
698
    {
699
        handleFadersEnd(timer);
3✔
700
        timer->unregisterDMXSource(this);
3✔
701
    }
702
}
5✔
703

704
/****************************************************************************
705
 * Running
706
 ****************************************************************************/
707

708
void Scene::processValue(MasterTimer *timer, QList<Universe*> ua, uint fadeIn, SceneValue &scv)
515✔
709
{
710
    Fixture *fixture = doc()->fixture(scv.fxi);
515✔
711

712
    if (fixture == NULL)
515✔
713
        return;
×
714

715
    int universeIndex = floor((fixture->universeAddress() + scv.channel) / 512);
515✔
716
    if (universeIndex >= ua.count())
515✔
717
        return;
718

719
    Universe *universe = ua.at(universeIndex);
515✔
720

721
    QSharedPointer<GenericFader> fader = m_fadersMap.value(universe->id(), QSharedPointer<GenericFader>());
515✔
722
    if (fader.isNull())
515✔
723
    {
724
        fader = universe->requestFader();
244✔
725
        fader->adjustIntensity(getAttributeValue(Intensity));
122✔
726
        fader->setBlendMode(blendMode());
122✔
727
        fader->setName(name());
122✔
728
        fader->setParentFunctionID(id());
122✔
729
        fader->setParentIntensity(getAttributeValue(ParentIntensity));
122✔
730
        fader->setHandleSecondary(true);
122✔
731
        m_fadersMap[universe->id()] = fader;
122✔
732
    }
733

734
    FadeChannel *fc = fader->getChannelFader(doc(), universe, scv.fxi, scv.channel);
515✔
735
    int chIndex = fc->channelIndex(scv.channel);
515✔
736

737
    /** If a blend Function has been set, check if this channel needs to
738
     *  be blended from a previous value. If so, mark it for crossfade
739
     *  and set its current value */
740
    if (blendFunctionID() != Function::invalidId())
515✔
741
    {
742
        Scene *blendScene = qobject_cast<Scene *>(doc()->function(blendFunctionID()));
407✔
743
        if (blendScene != NULL && blendScene->checkValue(scv))
407✔
744
        {
745
            fc->addFlag(FadeChannel::CrossFade);
407✔
746
            fc->setCurrent(blendScene->value(scv.fxi, scv.channel), chIndex);
407✔
747
            qDebug() << "----- BLEND from Scene" << blendScene->name()
748
                     << ", fixture:" << scv.fxi << ", channel:" << scv.channel << ", value:" << fc->current();
749
        }
750
    }
751
    else
752
    {
753
        qDebug() << "Scene" << name() << "add channel" << scv.channel << "from" << fc->current(chIndex) << "to" << scv.value;
754
    }
755

756
    fc->setStart(fc->current(chIndex), chIndex);
515✔
757
    fc->setTarget(scv.value, chIndex);
515✔
758

759
    if (fc->canFade() == false)
515✔
760
    {
761
        fc->setFadeTime(0);
×
762
    }
763
    else
764
    {
765
        if (tempoType() == Beats)
515✔
766
        {
767
            int fadeInTime = beatsToTime(fadeIn, timer->beatTimeDuration());
×
768
            int beatOffset = timer->nextBeatTimeOffset();
×
769

770
            if (fadeInTime - beatOffset > 0)
×
771
                fc->setFadeTime(fadeInTime - beatOffset);
×
772
            else
773
                fc->setFadeTime(fadeInTime);
×
774
        }
775
        else
776
        {
777
            fc->setFadeTime(fadeIn);
515✔
778
        }
779
    }
780
}
781

782
void Scene::handleFadersEnd(MasterTimer *timer)
111✔
783
{
784
    uint fadeout = overrideFadeOutSpeed() == defaultSpeed() ? fadeOutSpeed() : overrideFadeOutSpeed();
111✔
785

786
    /* If no fade out is needed, dismiss all the requested faders.
787
     * Otherwise, set all the faders to fade out and let Universe dismiss them
788
     * when done */
789
    if (fadeout == 0)
111✔
790
    {
791
        dismissAllFaders();
106✔
792
    }
793
    else
794
    {
795
        if (tempoType() == Beats)
5✔
796
            fadeout = beatsToTime(fadeout, timer->beatTimeDuration());
×
797

798
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
14✔
799
        {
800
            if (!fader.isNull())
4✔
801
                fader->setFadeOut(true, fadeout);
4✔
802
        }
803
    }
804

805
    m_fadersMap.clear();
111✔
806

807
    // autonomously reset a blend function if set
808
    setBlendFunctionID(Function::invalidId());
111✔
809
}
111✔
810

811
void Scene::write(MasterTimer *timer, QList<Universe*> ua)
402✔
812
{
813
    //qDebug() << Q_FUNC_INFO << elapsed();
814

815
    if (m_values.count() == 0 && m_palettes.count() == 0)
402✔
816
    {
817
        stop(FunctionParent::master());
1✔
818
        return;
1✔
819
    }
820

821
    if (m_fadersMap.isEmpty())
401✔
822
    {
823
        uint fadeIn = overrideFadeInSpeed() == defaultSpeed() ? fadeInSpeed() : overrideFadeInSpeed();
122✔
824

825
        foreach (quint32 paletteID, palettes())
244✔
826
        {
827
            QLCPalette *palette = doc()->palette(paletteID);
×
828
            if (palette == NULL)
×
829
                continue;
×
830

831
            foreach (SceneValue scv, palette->valuesFromFixtureGroups(doc(), fixtureGroups()))
×
832
                processValue(timer, ua, fadeIn, scv);
×
833

834
            foreach (SceneValue scv, palette->valuesFromFixtures(doc(), fixtures()))
×
835
                processValue(timer, ua, fadeIn, scv);
×
836
        }
837

838
        QMutexLocker locker(&m_valueListMutex);
122✔
839
        QMapIterator <SceneValue, uchar> it(m_values);
122✔
840
        while (it.hasNext() == true)
637✔
841
        {
842
            SceneValue scv(it.next().key());
515✔
843
            processValue(timer, ua, fadeIn, scv);
515✔
844
        }
515✔
845
    }
846

847
    if (isPaused() == false)
401✔
848
    {
849
        incrementElapsed();
398✔
850
        if (timer->isBeat() && tempoType() == Beats)
398✔
851
            incrementElapsedBeats();
×
852
    }
853
}
854

855
void Scene::postRun(MasterTimer* timer, QList<Universe *> ua)
108✔
856
{
857
    handleFadersEnd(timer);
108✔
858

859
    Function::postRun(timer, ua);
108✔
860
}
108✔
861

862
void Scene::setPause(bool enable)
6✔
863
{
864
    if (!isRunning())
6✔
865
        return;
866

867
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
14✔
868
    {
869
        if (!fader.isNull())
2✔
870
            fader->setPaused(enable);
2✔
871
    }
872
    Function::setPause(enable);
6✔
873
}
874

875
/****************************************************************************
876
 * Intensity
877
 ****************************************************************************/
878

879
int Scene::adjustAttribute(qreal fraction, int attributeId)
248✔
880
{
881
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
248✔
882

883
    if (attrIndex == Intensity)
248✔
884
    {
885
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
265✔
886
        {
887
            if (!fader.isNull())
3✔
888
                fader->adjustIntensity(getAttributeValue(Function::Intensity));
3✔
889
        }
890
    }
891
    else if (attrIndex == ParentIntensity)
117✔
892
    {
893
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
237✔
894
        {
895
            if (!fader.isNull())
3✔
896
                fader->setParentIntensity(getAttributeValue(ParentIntensity));
3✔
897
        }
898
    }
899

900
    return attrIndex;
248✔
901
}
902

903
/*************************************************************************
904
 * Blend mode
905
 *************************************************************************/
906

907
void Scene::setBlendMode(Universe::BlendMode mode)
3✔
908
{
909
    if (mode == blendMode())
3✔
910
        return;
911

912
    qDebug() << "Scene" << name() << "blend mode set to" << Universe::blendModeToString(mode);
913

914
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
4✔
915
    {
916
        if (!fader.isNull())
×
917
            fader->setBlendMode(mode);
×
918
    }
919

920
    Function::setBlendMode(mode);
2✔
921
}
922

923
quint32 Scene::blendFunctionID() const
922✔
924
{
925
    return m_blendFunctionID;
922✔
926
}
927

928
void Scene::setBlendFunctionID(quint32 fid)
204✔
929
{
930
    m_blendFunctionID = fid;
204✔
931
    if (isRunning() && fid == Function::invalidId())
204✔
932
    {
933
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
218✔
934
        {
935
            if (!fader.isNull())
×
936
                fader->resetCrossfade();
×
937
        }
938
    }
939
}
204✔
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