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

mcallegari / qlcplus / 6628997562

24 Oct 2023 03:21PM UTC coverage: 28.085% (+0.05%) from 28.038%
6628997562

Pull #1462

github

web-flow
Merge 231f6a87e into 646f68840
Pull Request #1462: Overriding flash functionality

91 of 91 new or added lines in 9 files covered. (100.0%)

15382 of 54770 relevant lines covered (28.08%)

20312.39 hits per line

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

76.69
/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 "qlcmacros.h"
29
#include "qlcfile.h"
30
#include "qlccapability.h"
31

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

39
/*****************************************************************************
40
 * Initialization
41
 *****************************************************************************/
42

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

52
Scene::~Scene()
396✔
53
{
54
}
396✔
55

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

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

66
/*****************************************************************************
67
 * Copying
68
 *****************************************************************************/
69

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

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

86
    return copy;
1✔
87
}
88

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

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

108
    return Function::copyFrom(function);
3✔
109
}
110

111
/*****************************************************************************
112
 * Values
113
 *****************************************************************************/
114

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

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

125
    {
126
        QMutexLocker locker(&m_valueListMutex);
1,108✔
127

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
    return ids;
1✔
216
}
217

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

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

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

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

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

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

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

281
    return QColor();
×
282
}
283

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

292
/*********************************************************************
293
 * Channel Groups
294
 *********************************************************************/
295

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

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

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

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

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

332
/*****************************************************************************
333
 * Fixtures
334
 *****************************************************************************/
335

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

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

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

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

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

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

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

374
/*********************************************************************
375
 * Fixture Groups
376
 *********************************************************************/
377

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

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

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

394
/*********************************************************************
395
 * Palettes
396
 *********************************************************************/
397

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

499
    return true;
4✔
500
}
501

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

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

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

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

609
    return true;
2✔
610
}
611

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

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

633
/****************************************************************************
634
 * Flashing
635
 ****************************************************************************/
636

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

642
    Q_ASSERT(timer != NULL);
5✔
643
    Function::flash(timer, override, forceLTP);
5✔
644
    timer->registerDMXSource(this);
5✔
645
}
646

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

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

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

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

673
                QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
6✔
674
                if (fader.isNull())
3✔
675
                {
676
                    fader = ua[universe]->requestFader();
1✔
677

678
                    if (m_flashOverrides)
1✔
679
                        fader->setPriority(Universe::Flashing);
×
680

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

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

703
/****************************************************************************
704
 * Running
705
 ****************************************************************************/
706

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

711
    if (fixture == NULL)
512✔
712
        return;
×
713

714
    quint32 universe = fixture->universe();
512✔
715
    if (universe == Universe::invalid())
512✔
716
        return;
×
717

718
    QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
1,024✔
719
    if (fader.isNull())
512✔
720
    {
721
        fader = ua[universe]->requestFader();
119✔
722
        fader->adjustIntensity(getAttributeValue(Intensity));
119✔
723
        fader->setBlendMode(blendMode());
119✔
724
        fader->setName(name());
119✔
725
        fader->setParentFunctionID(id());
119✔
726
        m_fadersMap[universe] = fader;
119✔
727

728
        fader->setParentIntensity(getAttributeValue(ParentIntensity));
119✔
729
    }
730

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

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

752
    fc->setStart(fc->current());
512✔
753
    fc->setTarget(scv.value);
512✔
754

755
    if (fc->canFade() == false)
512✔
756
    {
757
        fc->setFadeTime(0);
×
758
    }
759
    else
760
    {
761
        if (tempoType() == Beats)
512✔
762
        {
763
            int fadeInTime = beatsToTime(fadeIn, timer->beatTimeDuration());
×
764
            int beatOffset = timer->nextBeatTimeOffset();
×
765

766
            if (fadeInTime - beatOffset > 0)
×
767
                fc->setFadeTime(fadeInTime - beatOffset);
×
768
            else
769
                fc->setFadeTime(fadeInTime);
×
770
        }
771
        else
772
        {
773
            fc->setFadeTime(fadeIn);
512✔
774
        }
775
    }
776
}
777

778
void Scene::handleFadersEnd(MasterTimer *timer)
109✔
779
{
780
    uint fadeout = overrideFadeOutSpeed() == defaultSpeed() ? fadeOutSpeed() : overrideFadeOutSpeed();
109✔
781

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

794
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
18✔
795
        {
796
            if (!fader.isNull())
4✔
797
                fader->setFadeOut(true, fadeout);
4✔
798
        }
799
    }
800

801
    m_fadersMap.clear();
109✔
802

803
    // autonomously reset a blend function if set
804
    setBlendFunctionID(Function::invalidId());
109✔
805
}
109✔
806

807
void Scene::write(MasterTimer *timer, QList<Universe*> ua)
372✔
808
{
809
    //qDebug() << Q_FUNC_INFO << elapsed();
810

811
    if (m_values.count() == 0 && m_palettes.count() == 0)
372✔
812
    {
813
        stop(FunctionParent::master());
1✔
814
        return;
1✔
815
    }
816

817
    if (m_fadersMap.isEmpty())
371✔
818
    {
819
        uint fadeIn = overrideFadeInSpeed() == defaultSpeed() ? fadeInSpeed() : overrideFadeInSpeed();
119✔
820

821
        foreach (quint32 paletteID, palettes())
238✔
822
        {
823
            QLCPalette *palette = doc()->palette(paletteID);
×
824
            if (palette == NULL)
×
825
                continue;
×
826

827
            foreach (SceneValue scv, palette->valuesFromFixtureGroups(doc(), fixtureGroups()))
×
828
                processValue(timer, ua, fadeIn, scv);
×
829

830
            foreach (SceneValue scv, palette->valuesFromFixtures(doc(), fixtures()))
×
831
                processValue(timer, ua, fadeIn, scv);
×
832
        }
833

834
        QMutexLocker locker(&m_valueListMutex);
238✔
835
        QMapIterator <SceneValue, uchar> it(m_values);
238✔
836
        while (it.hasNext() == true)
631✔
837
        {
838
            SceneValue scv(it.next().key());
512✔
839
            processValue(timer, ua, fadeIn, scv);
512✔
840
        }
841
    }
842

843
    if (isPaused() == false)
371✔
844
    {
845
        incrementElapsed();
368✔
846
        if (timer->isBeat() && tempoType() == Beats)
368✔
847
            incrementElapsedBeats();
×
848
    }
849
}
850

851
void Scene::postRun(MasterTimer* timer, QList<Universe *> ua)
106✔
852
{
853
    handleFadersEnd(timer);
106✔
854

855
    Function::postRun(timer, ua);
106✔
856
}
106✔
857

858
void Scene::setPause(bool enable)
6✔
859
{
860
    if (!isRunning())
6✔
861
        return;
×
862

863
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
16✔
864
    {
865
        if (!fader.isNull())
2✔
866
            fader->setPaused(enable);
2✔
867
    }
868
    Function::setPause(enable);
6✔
869
}
870

871
/****************************************************************************
872
 * Intensity
873
 ****************************************************************************/
874

875
int Scene::adjustAttribute(qreal fraction, int attributeId)
242✔
876
{
877
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
242✔
878

879
    if (attrIndex == Intensity)
242✔
880
    {
881
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
252✔
882
        {
883
            if (!fader.isNull())
2✔
884
                fader->adjustIntensity(getAttributeValue(Function::Intensity));
2✔
885
        }
886
    }
887
    else if (attrIndex == ParentIntensity)
118✔
888
    {
889
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
230✔
890
        {
891
            if (!fader.isNull())
2✔
892
                fader->setParentIntensity(getAttributeValue(ParentIntensity));
2✔
893
        }
894
    }
895

896
    return attrIndex;
242✔
897
}
898

899
/*************************************************************************
900
 * Blend mode
901
 *************************************************************************/
902

903
void Scene::setBlendMode(Universe::BlendMode mode)
3✔
904
{
905
    if (mode == blendMode())
3✔
906
        return;
1✔
907

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

910
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
4✔
911
    {
912
        if (!fader.isNull())
×
913
            fader->setBlendMode(mode);
×
914
    }
915

916
    Function::setBlendMode(mode);
2✔
917
}
918

919
quint32 Scene::blendFunctionID() const
917✔
920
{
921
    return m_blendFunctionID;
917✔
922
}
923

924
void Scene::setBlendFunctionID(quint32 fid)
200✔
925
{
926
    m_blendFunctionID = fid;
200✔
927
    if (isRunning() && fid == Function::invalidId())
200✔
928
    {
929
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
214✔
930
        {
931
            if (!fader.isNull())
×
932
                fader->resetCrossfade();
×
933
        }
934
    }
935
}
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

© 2025 Coveralls, Inc