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

mcallegari / qlcplus / 13633248611

03 Mar 2025 02:31PM UTC coverage: 31.871% (+0.4%) from 31.5%
13633248611

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 hits per line

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

44.48
/ui/src/palettegenerator.cpp
1
/*
2
  Q Light Controller Plus
3
  palettegenerator.cpp
4

5
  Copyright (C) Massimo Callegari
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QString>
21
#include <QDebug>
22

23
#include "qlccapability.h"
24
#include "qlcfixturedef.h"
25
#include "qlcfixturehead.h"
26
#include "qlcchannel.h"
27

28
#include "palettegenerator.h"
29
#include "rgbscriptscache.h"
30
#include "fixturegroup.h"
31
#include "chaserstep.h"
32
#include "rgbmatrix.h"
33
#include "fixture.h"
34
#include "chaser.h"
35
#include "scene.h"
36
#include "doc.h"
37

38
PaletteGenerator::PaletteGenerator(Doc* doc, const QList <Fixture*>& fxList,
4✔
39
                                   PaletteType type, PaletteSubType subType)
4✔
40
    : m_doc(doc)
4✔
41
    , m_name(QString())
4✔
42
    , m_type(type)
4✔
43
    , m_subType(subType)
4✔
44
    , m_fixtures(fxList)
4✔
45
    , m_fixtureGroup(NULL)
4✔
46
{
47
    if (m_fixtures.count() > 0)
4✔
48
    {
49
        m_name = typetoString(type);
4✔
50
        if (m_fixtures.at(0)->fixtureDef() != NULL)
4✔
51
            m_model = m_fixtures.at(0)->fixtureDef()->model();
3✔
52
        if (type != Undefined)
4✔
53
            createFunctions(type, subType);
3✔
54
    }
55
}
4✔
56

57
PaletteGenerator::~PaletteGenerator()
4✔
58
{
59
    m_fixtures.clear();
4✔
60
    m_scenes.clear();
4✔
61
    m_chasers.clear();
4✔
62
    m_matrices.clear();
4✔
63
}
4✔
64

65
void PaletteGenerator::setName(QString name)
×
66
{
67
    m_name = name;
×
68
}
×
69

70
QString PaletteGenerator::name()
×
71
{
72
    return m_name;
×
73
}
74

75
QString PaletteGenerator::fullName()
×
76
{
77
    return m_name + " - " + m_model;
×
78
}
79

80
QString PaletteGenerator::model()
×
81
{
82
    return m_model;
×
83
}
84

85
PaletteGenerator::PaletteType PaletteGenerator::type()
×
86
{
87
    return m_type;
×
88
}
89

90
PaletteGenerator::PaletteSubType PaletteGenerator::subType()
×
91
{
92
    return m_subType;
×
93
}
94

95
QString PaletteGenerator::typetoString(PaletteGenerator::PaletteType type)
7✔
96
{
97
    switch(type)
7✔
98
    {
99
        case PrimaryColors: return tr("Primary colours"); break;
×
100
        case SixteenColors: return tr("16 Colours"); break;
×
101
        case Shutter: return tr("Shutter macros");
2✔
102
        case Gobos: return tr("Gobo macros");
2✔
103
        case ColourMacro: return tr("Colour macros");
2✔
104
        case Animation: return tr("Animations");
×
105
        case Undefined:
1✔
106
        default:
107
            return tr("Unknown");
108
        break;
109
    }
110
}
111

112
QStringList PaletteGenerator::getCapabilities(const Fixture *fixture)
2✔
113
{
114
    QStringList caps;
115
    bool hasPan = false, hasTilt = false;
116
    bool hasRed = false, hasGreen = false, hasBlue = false;
117
    bool hasCyan = false, hasMagenta = false, hasYellow = false;
118
    bool hasWhite = false;
119

120
    Q_ASSERT(fixture != NULL);
121
    for (quint32 ch = 0; ch < fixture->channels(); ch++)
17✔
122
    {
123
        const QLCChannel* channel(fixture->channel(ch));
15✔
124
        Q_ASSERT(channel != NULL);
125

126
        switch (channel->group())
15✔
127
        {
128
            case QLCChannel::Colour:
4✔
129
            case QLCChannel::Gobo:
130
            case QLCChannel::Shutter:
131
            {
132
                if (channel->capabilities().size() > 1)
4✔
133
                {
134
                    QString cap = QLCChannel::groupToString(channel->group());
4✔
135
                    if (!caps.contains(cap))
4✔
136
                        caps.append(cap);
4✔
137
                }
4✔
138
            }
139
            break;
140
            case QLCChannel::Pan:
2✔
141
                hasPan = true;
142
            break;
2✔
143
            case QLCChannel::Tilt:
2✔
144
                hasTilt = true;
145
            break;
2✔
146
            case QLCChannel::Intensity:
5✔
147
            {
148
                QLCChannel::PrimaryColour col = channel->colour();
5✔
149
                switch (col)
150
                {
151
                    case QLCChannel::Red: hasRed = true; break;
×
152
                    case QLCChannel::Green: hasGreen = true; break;
×
153
                    case QLCChannel::Blue: hasBlue = true; break;
×
154
                    case QLCChannel::Cyan: hasCyan = true; break;
1✔
155
                    case QLCChannel::Magenta: hasMagenta = true; break;
1✔
156
                    case QLCChannel::Yellow: hasYellow = true; break;
1✔
157
                    case QLCChannel::White: hasWhite = true; break;
×
158
                    default: break;
159
                }
160
            }
161
            break;
162
            default:
163
            break;
164
        }
165
    }
166

167
    if (hasPan && hasTilt)
2✔
168
        caps.append(KQLCChannelMovement);
2✔
169

170
    if (hasRed && hasGreen && hasBlue)
2✔
171
        caps.append(KQLCChannelRGB);
×
172

173
    if (hasCyan && hasMagenta && hasYellow)
2✔
174
        caps.append(KQLCChannelCMY);
1✔
175

176
    if (hasWhite)
2✔
177
        caps.append(KQLCChannelWhite);
×
178

179
    return caps;
2✔
180
}
181

182
QList<Scene *> PaletteGenerator::scenes()
×
183
{
184
    return m_scenes;
×
185
}
186

187
QList<Chaser *> PaletteGenerator::chasers()
×
188
{
189
    return m_chasers;
×
190
}
191

192
QList<RGBMatrix *> PaletteGenerator::matrices()
×
193
{
194
    return m_matrices;
×
195
}
196

197
void PaletteGenerator::addToDoc()
3✔
198
{
199
    foreach (Scene *scene, m_scenes)
36✔
200
        m_doc->addFunction(scene);
33✔
201

202
    foreach (Chaser *chaser, m_chasers)
6✔
203
    {
204
        foreach (Scene *scene, m_scenes)
36✔
205
        {
206
            qDebug() << "Add chaser step:" << scene->id();
207
            chaser->addStep(ChaserStep(scene->id()));
66✔
208
        }
209
        m_doc->addFunction(chaser);
3✔
210
    }
211

212
    if (m_fixtureGroup != NULL)
3✔
213
        m_doc->addFixtureGroup(m_fixtureGroup);
×
214

215
    foreach (RGBMatrix *matrix, m_matrices)
3✔
216
    {
217
        matrix->setFixtureGroup(m_fixtureGroup->id());
×
218
        m_doc->addFunction(matrix);
×
219
    }
220
}
3✔
221

222
void PaletteGenerator::createColorScene(QList<SceneValue> chMap, QString name, PaletteSubType subType)
×
223
{
224
    if (chMap.size() == 0)
×
225
        return;
×
226

227
    Scene *scene = new Scene(m_doc);
×
228
    Scene *evenScene = NULL;
×
229
    Scene *oddScene = NULL;
×
230
    bool even = false;
231

232
    if (subType == OddEven)
×
233
    {
234
        evenScene = new Scene(m_doc);
×
235
        oddScene = new Scene(m_doc);
×
236
    }
237

238
    foreach (SceneValue scv, chMap)
×
239
    {
240

241
        scene->setValue(scv.fxi, scv.channel, 255);
×
242
        if (subType == OddEven)
×
243
        {
244
            if (even)
×
245
                evenScene->setValue(scv.fxi, scv.channel, 255);
×
246
            else
247
                oddScene->setValue(scv.fxi, scv.channel, 255);
×
248
            even = !even;
×
249
        }
250
    }
×
251
    scene->setName(getNamePrefix("Color", name));
×
252
    m_scenes.append(scene);
×
253
    if (subType == OddEven)
×
254
    {
255
        evenScene->setName(tr("%1 (Even)").arg(getNamePrefix("Color", name)));
×
256
        oddScene->setName(tr("%1 (Odd)").arg(getNamePrefix("Color", name)));
×
257
        m_scenes.append(evenScene);
×
258
        m_scenes.append(oddScene);
×
259
    }
260
}
261

262
void PaletteGenerator::createRGBCMYScene(QList<SceneValue> rcMap,
×
263
                                         QList<SceneValue> gmMap,
264
                                         QList<SceneValue> byMap,
265
                                         QString name, bool rgb,
266
                                         PaletteGenerator::PaletteSubType subType)
267
{
268
    if (rcMap.size() == 0 || gmMap.size() == 0 || byMap.size() == 0)
×
269
        return;
×
270

271
    bool even = false;
272
    QList <QColor> m_colList;
273
    QList <QString> m_colNames;
274

275
    m_colList << Qt::black << Qt::darkBlue << Qt::blue << Qt::darkGreen <<
×
276
                 Qt::darkCyan << Qt::green << Qt::cyan << Qt::darkRed <<
×
277
                 Qt::darkMagenta << Qt::darkYellow << Qt::darkGray << Qt::lightGray <<
×
278
                 Qt::red << Qt::magenta << Qt::yellow << Qt::white;
×
279

280
    m_colNames << tr("Black") << tr("Dark Blue") << tr("Blue") << tr("Dark Green")
×
281
               << tr("Dark Cyan") << tr("Green") << tr("Cyan") << tr("Dark Red")
×
282
               << tr("Dark Magenta") << tr("Dark Yellow") << tr("Dark Gray") << tr("Light Gray")
×
283
               << tr("Red") << tr("Magenta") << tr("Yellow") << tr("White");
×
284

285
    for (int i = 0; i < m_colList.count(); i++)
×
286
    {
287
        QColor col = m_colList.at(i);
288
        uchar rc = col.red();
×
289
        uchar gm = col.green();
×
290
        uchar by = col.blue();
×
291
        if (rgb == false)
×
292
        {
293
            rc = col.cyan();
×
294
            gm = col.magenta();
×
295
            by = col.yellow();
×
296
        }
297

298
        Scene *scene = new Scene(m_doc);
×
299
        Scene *evenScene = NULL;
×
300
        Scene *oddScene = NULL;
×
301

302
        if (subType == OddEven)
×
303
        {
304
            evenScene = new Scene(m_doc);
×
305
            oddScene = new Scene(m_doc);
×
306
        }
307

308
        foreach (SceneValue scv, rcMap)
×
309
        {
310
            Fixture *fxi = m_doc->fixture(scv.fxi);
×
311
            int gmCh = -1, byCh = -1;
312

313
            for (int i = 0; i < fxi->heads(); i++)
×
314
            {
315
                QLCFixtureHead head = fxi->head(i);
×
316
                if (head.channels().contains(scv.channel))
×
317
                {
318
                    if (head.rgbChannels().count() == 3)
×
319
                    {
320
                        gmCh = head.rgbChannels().at(1);
×
321
                        byCh = head.rgbChannels().at(2);
×
322
                    }
323
                    else if (head.cmyChannels().count() == 3)
×
324
                    {
325
                        gmCh = head.cmyChannels().at(1);
×
326
                        byCh = head.cmyChannels().at(2);
×
327
                    }
328
                    break;
329
                }
330
            }
×
331

332
            // if no green/magenta or no blue/yellow channels
333
            // are found, there's no chance to set a full RGB/CMY color
334
            if (gmCh == -1 || byCh == -1)
×
335
                continue;
336

337
            scene->setValue(scv.fxi, scv.channel, rc);
×
338
            scene->setValue(scv.fxi, gmCh, gm);
×
339
            scene->setValue(scv.fxi, byCh, by);
×
340

341
            if (subType == OddEven)
×
342
            {
343
                if (even)
×
344
                {
345
                    evenScene->setValue(scv.fxi, scv.channel, rc);
×
346
                    evenScene->setValue(scv.fxi, gmCh, gm);
×
347
                    evenScene->setValue(scv.fxi, byCh, by);
×
348
                }
349
                else
350
                {
351
                    oddScene->setValue(scv.fxi, scv.channel, rc);
×
352
                    oddScene->setValue(scv.fxi, gmCh, gm);
×
353
                    oddScene->setValue(scv.fxi, byCh, by);
×
354
                }
355
                even = !even;
×
356
            }
357
        }
×
358
        qDebug() << "color name:" << m_colNames.at(i) << "i:" << i << "count:" << m_colNames.count();
359

360
        scene->setName(getNamePrefix(m_colNames.at(i), name));
×
361
        m_scenes.append(scene);
×
362
        if (subType == OddEven)
×
363
        {
364
            evenScene->setName(tr("%1 (Even)").arg(getNamePrefix(m_colNames.at(i),name)));
×
365
            oddScene->setName(tr("%1 (Odd)").arg(getNamePrefix(m_colNames.at(i),name)));
×
366
            m_scenes.append(evenScene);
×
367
            m_scenes.append(oddScene);
×
368
        }
369
    }
370
}
×
371

372
void PaletteGenerator::createCapabilityScene(QHash<quint32, quint32> chMap,
3✔
373
                                             PaletteGenerator::PaletteSubType subType)
374
{
375
    if (chMap.size() == 0)
3✔
376
        return;
×
377

378
    Fixture *fxi = m_fixtures.at(0);
3✔
379
    Q_ASSERT(fxi != NULL);
380
    QHashIterator <quint32, quint32> it(chMap);
3✔
381

382
    quint32 ch = it.next().value();
3✔
383
    const QLCChannel* channel = fxi->channel(ch);
3✔
384
    QStringList tmpCapList;
385

386
    for (int cIdx = 0; cIdx < channel->capabilities().count(); cIdx++)
42✔
387
    {
388
        Scene *scene = new Scene(m_doc);
39✔
389
        Scene *evenScene = NULL;
39✔
390
        Scene *oddScene = NULL;
39✔
391
        bool even = false;
392
        QLCCapability *cap = channel->capabilities().at(cIdx);
39✔
393
        uchar value = cap->middle();
39✔
394
        QString name = cap->name();
39✔
395

396
        // Do not add the same capability twice
397
        if (tmpCapList.contains(name))
39✔
398
            continue;
399

400
        tmpCapList.append(name);
33✔
401

402
        if (subType == OddEven)
33✔
403
        {
404
            evenScene = new Scene(m_doc);
×
405
            oddScene = new Scene(m_doc);
×
406
        }
407

408
        QHashIterator <quint32, quint32> it(chMap);
33✔
409
        while (it.hasNext() == true)
99✔
410
        {
411
            it.next();
66✔
412
            scene->setValue(it.key(), it.value(), value);
66✔
413
            if (subType == OddEven)
66✔
414
            {
415
                if (even)
×
416
                    evenScene->setValue(it.key(), it.value(), value);
×
417
                else
418
                    oddScene->setValue(it.key(), it.value(), value);
×
419
                even = !even;
×
420
            }
421
        }
422

423
        scene->setName(getNamePrefix(channel->name(),  name));
33✔
424
        m_scenes.append(scene);
33✔
425
        if (subType == OddEven)
33✔
426
        {
427
            evenScene->setName(getNamePrefix(channel->name(),  name) + tr(" - Even"));
×
428
            oddScene->setName(getNamePrefix(channel->name(),  name) + tr(" - Odd"));
×
429
            m_scenes.append(evenScene);
×
430
            m_scenes.append(oddScene);
×
431
        }
432
    }
39✔
433
}
434

435
void PaletteGenerator::createRGBMatrices(QList<SceneValue> rgbMap)
×
436
{
437
    m_fixtureGroup = new FixtureGroup(m_doc);
×
438
    m_fixtureGroup->setSize(QSize(rgbMap.size(), 1));
×
439

440
    foreach (SceneValue scv, rgbMap)
×
441
    {
442
        m_fixtureGroup->assignFixture(scv.fxi);
×
443
        m_fixtureGroup->setName(m_model + tr(" - RGB Group"));
×
444
    }
×
445
    QStringList algoList = m_doc->rgbScriptsCache()->names();
×
446
    foreach (QString algo, algoList)
×
447
    {
448
        RGBMatrix *matrix = new RGBMatrix(m_doc);
×
449
        matrix->setName(tr("Animation %1").arg(algo) + " - " + m_model);
×
450
        //matrix->setFixtureGroup();
451
        matrix->setAlgorithm(RGBAlgorithm::algorithm(m_doc, algo));
×
452
        m_matrices.append(matrix);
×
453
    }
×
454
}
×
455

456
void PaletteGenerator::createChaser(QString name)
3✔
457
{
458
    if (m_scenes.count() == 0)
3✔
459
        return;
×
460

461
    Chaser *chaser = new Chaser(m_doc);
3✔
462
    chaser->setFadeInMode(Chaser::Common);
3✔
463
    chaser->setFadeInSpeed(3000);
3✔
464
    chaser->setFadeOutMode(Chaser::Common);
3✔
465
    chaser->setFadeOutSpeed(0);
3✔
466
    chaser->setDurationMode(Chaser::Common);
3✔
467
    chaser->setDuration(10000);
3✔
468
    chaser->setName(tr("%1 chaser - %2").arg(name).arg(m_model));
3✔
469

470
    // that's all here. I need to add an empty Chaser cause
471
    // scene's IDs have not been assigned yet
472
    m_chasers.append(chaser);
3✔
473
}
474

475
void PaletteGenerator::createFunctions(PaletteGenerator::PaletteType type,
3✔
476
                                       PaletteGenerator::PaletteSubType subType)
477
{
478
    if (m_fixtures.count() == 0)
3✔
479
        return;
×
480

481
    // the following QHash will hold the fixture/channel map of each fixture
482
    // in m_fixtures depending on type and subtype
483
    QHash<quint32, quint32> m_panList;
484
    QHash<quint32, quint32> m_tiltList;
485
    QList<SceneValue> m_redList;
486
    QList<SceneValue> m_greenList;
487
    QList<SceneValue> m_blueList;
488
    QList<SceneValue> m_cyanList;
489
    QList<SceneValue> m_magentaList;
490
    QList<SceneValue> m_yellowList;
491
    QList<SceneValue> m_whiteList;
492
    QHash<quint32, quint32> m_goboList;
493
    QHash<quint32, quint32> m_shutterList;
494
    QHash<quint32, quint32> m_colorMacroList;
495

496
    for (int i = 0; i < m_fixtures.count(); i++)
9✔
497
    {
498
        Fixture *fixture = m_fixtures.at(i);
6✔
499
        Q_ASSERT(fixture != NULL);
500
        quint32 fxID = fixture->id();
6✔
501

502
        for (quint32 ch = 0; ch < fixture->channels(); ch++)
48✔
503
        {
504
            const QLCChannel* channel(fixture->channel(ch));
42✔
505
            Q_ASSERT(channel != NULL);
506

507
            switch (channel->group())
42✔
508
            {
509
                case QLCChannel::Pan: m_panList[fxID] = ch; break;
6✔
510
                case QLCChannel::Tilt: m_tiltList[fxID] = ch; break;
6✔
511
                case QLCChannel::Gobo: m_goboList[fxID] = ch; break;
4✔
512
                case QLCChannel::Shutter: m_shutterList[fxID] = ch; break;
2✔
513
                case QLCChannel::Colour: m_colorMacroList[fxID] = ch; break;
6✔
514
                case QLCChannel::Intensity:
12✔
515
                {
516
                    QLCChannel::PrimaryColour col = channel->colour();
12✔
517
                    switch (col)
518
                    {
519
                        case QLCChannel::Red: m_redList.append(SceneValue(fxID, ch)); break;
×
520
                        case QLCChannel::Green: m_greenList.append(SceneValue(fxID, ch)); break;
×
521
                        case QLCChannel::Blue: m_blueList.append(SceneValue(fxID, ch)); break;
×
522
                        case QLCChannel::Cyan: m_cyanList.append(SceneValue(fxID, ch)); break;
2✔
523
                        case QLCChannel::Magenta: m_magentaList.append(SceneValue(fxID, ch)); break;
2✔
524
                        case QLCChannel::Yellow: m_yellowList.append(SceneValue(fxID, ch)); break;
2✔
525
                        case QLCChannel::White: m_whiteList.append(SceneValue(fxID, ch)); break;
×
526
                        default: break;
527
                    }
528
                }
529
                break;
530
                default:
531
                break;
532
            }
533
        }
534
    }
535

536
    switch (type)
3✔
537
    {
538
        case PrimaryColors:
×
539
        {
540
            createColorScene(m_redList, tr("Red scene"), subType);
×
541
            createColorScene(m_greenList, tr("Green scene"), subType);
×
542
            createColorScene(m_blueList, tr("Blue scene"), subType);
×
543
            createColorScene(m_cyanList, tr("Cyan scene"), subType);
×
544
            createColorScene(m_magentaList, tr("Magenta scene"), subType);
×
545
            createColorScene(m_yellowList, tr("Yellow scene"), subType);
×
546
            createColorScene(m_whiteList, tr("White scene"), subType);
×
547
            createChaser(typetoString(type));
×
548
        }
549
        break;
×
550
        case SixteenColors:
551
        {
552
            if (m_redList.size() > 0 && m_greenList.size() == m_redList.size() && m_blueList.size() ==  m_redList.size())
×
553
                createRGBCMYScene(m_redList, m_greenList, m_blueList, tr("Scene"), true, subType);
×
554
            else if (m_cyanList.size() > 0 && m_magentaList.size() == m_cyanList.size() && m_yellowList.size() ==  m_cyanList.size())
×
555
                createRGBCMYScene(m_cyanList, m_magentaList, m_yellowList, tr("Scene"), false, subType);
×
556
            createChaser(typetoString(type));
×
557
        }
558
        break;
×
559
        case Animation:
560
        {
561
            if (m_redList.size() > 1 && m_greenList.size() == m_redList.size() && m_blueList.size() ==  m_redList.size())
×
562
                createRGBMatrices(m_redList);
×
563
        }
564
        break;
565
        case Gobos:
1✔
566
        {
567
            createCapabilityScene(m_goboList, subType);
1✔
568
            createChaser(typetoString(type));
1✔
569
        }
570
        break;
1✔
571
        case Shutter:
1✔
572
        {
573
            createCapabilityScene(m_shutterList, subType);
1✔
574
            createChaser(typetoString(type));
1✔
575
        }
576
        break;
1✔
577
        case ColourMacro:
1✔
578
        {
579
            createCapabilityScene(m_colorMacroList, subType);
1✔
580
            createChaser(typetoString(type));
1✔
581
        }
582
        break;
1✔
583
        case Undefined:
584
        default:
585
        break;
586

587
    }
588
}
3✔
589

590
QString PaletteGenerator::getNamePrefix(QString name)
×
591
{
592
    // return name + " - " + m_model; // old naming
593
    return m_model + " - " + name;
×
594
}
595

596
QString PaletteGenerator::getNamePrefix(QString type, QString name)
33✔
597
{
598
    // return name + " - " + type + " - " + m_model; // old naming
599
    return m_model + " - " + type + " - " + name;
33✔
600
}
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

© 2026 Coveralls, Inc