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

mcallegari / qlcplus / 6786820899

07 Nov 2023 03:39PM UTC coverage: 28.09% (+0.02%) from 28.067%
6786820899

Pull #1462

github

web-flow
Merge a2abb737c into d187efff6
Pull Request #1462: Overriding flash functionality

28 of 42 new or added lines in 5 files covered. (66.67%)

2 existing lines in 1 file now uncovered.

15407 of 54849 relevant lines covered (28.09%)

20304.0 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 "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, bool shouldOverride, bool forceLTP)
6✔
636
{
637
    if (flashing() == true)
6✔
638
        return;
1✔
639

640
    Q_ASSERT(timer != NULL);
5✔
641
    Function::flash(timer, shouldOverride, forceLTP);
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

676
                    if (m_flashOverrides)
1✔
NEW
677
                        fader->setPriority(Universe::Flashing);
×
678

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

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

701
/****************************************************************************
702
 * Running
703
 ****************************************************************************/
704

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

709
    if (fixture == NULL)
512✔
710
        return;
×
711

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

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

726
        fader->setParentIntensity(getAttributeValue(ParentIntensity));
119✔
727
    }
728

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

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

750
    fc->setStart(fc->current());
512✔
751
    fc->setTarget(scv.value);
512✔
752

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

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

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

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

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

799
    m_fadersMap.clear();
109✔
800

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

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

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

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

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

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

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

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

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

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

853
    Function::postRun(timer, ua);
106✔
854
}
106✔
855

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

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

869
/****************************************************************************
870
 * Intensity
871
 ****************************************************************************/
872

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

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

894
    return attrIndex;
242✔
895
}
896

897
/*************************************************************************
898
 * Blend mode
899
 *************************************************************************/
900

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

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

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

914
    Function::setBlendMode(mode);
2✔
915
}
916

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

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