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

mcallegari / qlcplus / 6796513551

08 Nov 2023 09:52AM UTC coverage: 28.09% (+0.02%) from 28.067%
6796513551

Pull #1462

github

web-flow
Merge b9be672c4 into 63469273b
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.79
/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_flashOverrides(false)
45
    , m_flashForceLTP(false)
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 shouldOverride, bool forceLTP)
6✔
638
{
639
    if (flashing() == true)
6✔
640
        return;
1✔
641

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

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

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

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

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

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

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

681
                    if (m_flashOverrides)
1✔
NEW
682
                        fader->setPriority(Universe::Flashing);
×
683

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

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

706
/****************************************************************************
707
 * Running
708
 ****************************************************************************/
709

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

714
    if (fixture == NULL)
512✔
715
        return;
×
716

717
    quint32 universe = fixture->universe();
512✔
718
    if (universe == Universe::invalid())
512✔
719
        return;
×
720

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

731
        fader->setParentIntensity(getAttributeValue(ParentIntensity));
119✔
732
    }
733

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

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

755
    fc->setStart(fc->current());
512✔
756
    fc->setTarget(scv.value);
512✔
757

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

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

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

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

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

804
    m_fadersMap.clear();
109✔
805

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

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

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

820
    if (m_fadersMap.isEmpty())
371✔
821
    {
822
        uint fadeIn = overrideFadeInSpeed() == defaultSpeed() ? fadeInSpeed() : overrideFadeInSpeed();
119✔
823

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

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

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

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

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

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

858
    Function::postRun(timer, ua);
106✔
859
}
106✔
860

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

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

874
/****************************************************************************
875
 * Intensity
876
 ****************************************************************************/
877

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

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

899
    return attrIndex;
242✔
900
}
901

902
/*************************************************************************
903
 * Blend mode
904
 *************************************************************************/
905

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

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

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

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

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

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