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

mcallegari / qlcplus / 6810307726

09 Nov 2023 10:11AM UTC coverage: 28.086% (+0.02%) from 28.067%
6810307726

Pull #1477

github

web-flow
Merge c8f4c4dcb into 56a703a42
Pull Request #1477: Webaccess cuelist side fader

8 of 39 new or added lines in 1 file covered. (20.51%)

279 existing lines in 9 files now uncovered.

15420 of 54903 relevant lines covered (28.09%)

20284.04 hits per line

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

76.91
/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
{
UNCOV
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
    {
UNCOV
77
        delete copy;
×
UNCOV
78
        copy = NULL;
×
79
    }
80
    if (addToDoc == true && doc->addFunction(copy) == false)
1✔
81
    {
UNCOV
82
        delete copy;
×
UNCOV
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✔
UNCOV
232
            continue;
×
233

234
        const QLCChannel* channel = fixture->channel(scv.channel);
8✔
235
        if (channel == NULL)
8✔
UNCOV
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✔
UNCOV
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✔
UNCOV
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

UNCOV
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)
×
UNCOV
381
        m_fixtureGroups.append(id);
×
382
}
×
383

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

389
QList<quint32> Scene::fixtureGroups() const
×
390
{
UNCOV
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)
×
UNCOV
401
        m_palettes.append(id);
×
402
}
×
403

404
bool Scene::removePalette(quint32 id)
×
405
{
UNCOV
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
    {
UNCOV
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);
×
UNCOV
440
            int val = m_channelGroupsLevels.at(i);
×
441
            chanGroupsIDs.append(QString("%1,%2").arg(id).arg(val));
×
442
        }
UNCOV
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
UNCOV
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);
×
UNCOV
484
        doc->writeAttribute(KXMLQLCFixtureGroupID, QString::number(groupId));
×
UNCOV
485
        doc->writeEndElement();
×
486
    }
487

488
    /* Save referenced Palettes */
489
    foreach (quint32 pId, m_palettes)
2✔
490
    {
491
        doc->writeStartElement(KXMLQLCPalette);
×
UNCOV
492
        doc->writeAttribute(KXMLQLCPaletteID, QString::number(pId));
×
UNCOV
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
        {
UNCOV
539
            QString chGrpIDs = root.readElementText();
×
540
            if (chGrpIDs.isEmpty() == false)
×
541
            {
UNCOV
542
                QStringList grpArray = chGrpIDs.split(",");
×
543
                foreach(QString grp, grpArray)
×
544
                {
UNCOV
545
                    m_channelGroups.append(grp.toUInt());
×
UNCOV
546
                    m_channelGroupsLevels.append(0);
×
547
                }
548
            }
549
        }
550
        else if (root.name() == KXMLQLCSceneChannelGroupsValues)
4✔
551
        {
UNCOV
552
            QString chGrpIDs = root.readElementText();
×
553
            if (chGrpIDs.isEmpty() == false)
×
554
            {
UNCOV
555
                QStringList grpArray = chGrpIDs.split(",");
×
556
                for (int i = 0; i + 1 < grpArray.count(); i+=2)
×
557
                {
UNCOV
558
                    m_channelGroups.append(grpArray.at(i).toUInt());
×
UNCOV
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);
×
UNCOV
576
            QString strvals = root.readElementText();
×
577
            if (strvals.isEmpty() == false)
×
578
            {
UNCOV
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();
×
UNCOV
585
                    scv.value = uchar(QString(varray.at(i + 1)).toInt());
×
UNCOV
586
                    setValue(scv);
×
587
                }
588
            }
589
        }
590
        else if (root.name() == KXMLQLCFixtureGroup)
1✔
591
        {
592
            quint32 id = root.attributes().value(KXMLQLCFixtureGroupID).toString().toUInt();
×
UNCOV
593
            addFixtureGroup(id);
×
UNCOV
594
            root.skipCurrentElement();
×
595
        }
596
        else if (root.name() == KXMLQLCPalette)
1✔
597
        {
598
            quint32 id = root.attributes().value(KXMLQLCPaletteID).toString().toUInt();
×
UNCOV
599
            addPalette(id);
×
UNCOV
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

UNCOV
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);
×
UNCOV
618
        setFadeInSpeed((value / MasterTimer::frequency()) * 1000);
×
UNCOV
619
        setFadeOutSpeed((value / MasterTimer::frequency()) * 1000);
×
620
    }
621

622
    // Remove such fixtures and channels that don't exist
UNCOV
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);
×
UNCOV
628
        if (fxi == NULL || fxi->channel(value.channel) == NULL)
×
629
            it.remove();
×
630
    }
UNCOV
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✔
UNCOV
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✔
UNCOV
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(m_flashOverrides ? Universe::Flashing : Universe::Auto);
1✔
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✔
UNCOV
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✔
UNCOV
712
        return;
×
713

714
    quint32 universe = fixture->universe();
512✔
715
    if (universe == Universe::invalid())
512✔
UNCOV
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
    {
UNCOV
757
        fc->setFadeTime(0);
×
758
    }
759
    else
760
    {
761
        if (tempoType() == Beats)
512✔
762
        {
UNCOV
763
            int fadeInTime = beatsToTime(fadeIn, timer->beatTimeDuration());
×
UNCOV
764
            int beatOffset = timer->nextBeatTimeOffset();
×
765

UNCOV
766
            if (fadeInTime - beatOffset > 0)
×
UNCOV
767
                fc->setFadeTime(fadeInTime - beatOffset);
×
768
            else
UNCOV
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✔
UNCOV
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);
×
UNCOV
824
            if (palette == NULL)
×
UNCOV
825
                continue;
×
826

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

UNCOV
830
            foreach (SceneValue scv, palette->valuesFromFixtures(doc(), fixtures()))
×
UNCOV
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✔
UNCOV
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✔
UNCOV
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
    {
UNCOV
912
        if (!fader.isNull())
×
UNCOV
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
        {
UNCOV
931
            if (!fader.isNull())
×
UNCOV
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