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

mcallegari / qlcplus / 7252848206

18 Dec 2023 07:26PM UTC coverage: 32.067% (+0.001%) from 32.066%
7252848206

push

github

mcallegari
Code style review #1427

199 of 628 new or added lines in 101 files covered. (31.69%)

8 existing lines in 2 files now uncovered.

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

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

61.47
/ui/src/virtualconsole/vccuelist.cpp
1
/*
2
  Q Light Controller Plus
3
  vccuelist.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 <QStyledItemDelegate>
22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QTreeWidgetItem>
25
#include <QFontMetrics>
26
#include <QProgressBar>
27
#include <QTreeWidget>
28
#include <QHeaderView>
29
#include <QGridLayout>
30
#include <QSettings>
31
#include <QCheckBox>
32
#include <QString>
33
#include <QLabel>
34
#include <QDebug>
35
#include <QTimer>
36

37
#include "vccuelistproperties.h"
38
#include "vcpropertieseditor.h"
39
#include "clickandgoslider.h"
40
#include "chaserrunner.h"
41
#include "mastertimer.h"
42
#include "chaserstep.h"
43
#include "vccuelist.h"
44
#include "qlcmacros.h"
45
#include "function.h"
46
#include "vcwidget.h"
47
#include "apputil.h"
48
#include "chaser.h"
49
#include "qmath.h"
50
#include "doc.h"
51

52
#define COL_NUM      0
53
#define COL_NAME     1
54
#define COL_FADEIN   2
55
#define COL_FADEOUT  3
56
#define COL_DURATION 4
57
#define COL_NOTES    5
58

59
#define PROP_ID  Qt::UserRole
60
#define HYSTERESIS 3 // Hysteresis for next/previous external input
61

62
#define PROGRESS_INTERVAL 200
63
#define UPDATE_TIMEOUT 100
64

65
const quint8 VCCueList::nextInputSourceId = 0;
66
const quint8 VCCueList::previousInputSourceId = 1;
67
const quint8 VCCueList::playbackInputSourceId = 2;
68
const quint8 VCCueList::sideFaderInputSourceId = 3;
69
const quint8 VCCueList::stopInputSourceId = 4;
70

71
const QString progressDisabledStyle =
72
        "QProgressBar { border: 2px solid #C3C3C3; border-radius: 4px; background-color: #DCDCDC; }";
73
const QString progressFadeStyle =
74
        "QProgressBar { border: 2px solid grey; border-radius: 4px; background-color: #C3C3C3; text-align: center; }"
75
        "QProgressBar::chunk { background-color: #63C10B; width: 1px; }";
76
const QString progressHoldStyle =
77
        "QProgressBar { border: 2px solid grey; border-radius: 4px; background-color: #C3C3C3; text-align: center; }"
78
        "QProgressBar::chunk { background-color: #0F9BEC; width: 1px; }";
79

80
const QString cfLabelBlueStyle =
81
        "QLabel { background-color: #4E8DDE; color: white; border: 1px solid; border-radius: 3px; font: bold; }";
82
const QString cfLabelOrangeStyle =
83
        "QLabel { background-color: orange; color: black; border: 1px solid; border-radius: 3px; font: bold; }";
84
const QString cfLabelNoStyle =
85
        "QLabel { border: 1px solid; border-radius: 3px; font: bold; }";
86

87
VCCueList::VCCueList(QWidget *parent, Doc *doc) : VCWidget(parent, doc)
15✔
88
    , m_chaserID(Function::invalidId())
30✔
89
    , m_nextPrevBehavior(DefaultRunFirst)
90
    , m_playbackLayout(PlayPauseStop)
91
    , m_timer(NULL)
92
    , m_primaryIndex(0)
93
    , m_secondaryIndex(0)
94
    , m_primaryTop(true)
95
    , m_slidersMode(None)
15✔
96
{
97
    /* Set the class name "VCCueList" as the object name as well */
98
    setObjectName(VCCueList::staticMetaObject.className());
15✔
99

100
    /* Create a layout for this widget */
101
    QGridLayout *grid = new QGridLayout(this);
15✔
102
    grid->setSpacing(2);
15✔
103

104
    QFontMetrics m_fm = QFontMetrics(this->font());
30✔
105

106
    m_topPercentageLabel = new QLabel("100%");
15✔
107
    m_topPercentageLabel->setAlignment(Qt::AlignHCenter);
15✔
108
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
109
    m_topPercentageLabel->setFixedWidth(m_fm.width("100%"));
110
#else
111
    m_topPercentageLabel->setFixedWidth(m_fm.horizontalAdvance("100%"));
15✔
112
#endif
113
    grid->addWidget(m_topPercentageLabel, 1, 0, 1, 1);
15✔
114

115
    m_topStepLabel = new QLabel("");
15✔
116
    m_topStepLabel->setStyleSheet(cfLabelNoStyle);
15✔
117
    m_topStepLabel->setAlignment(Qt::AlignCenter);
15✔
118
    m_topStepLabel->setFixedSize(32, 24);
15✔
119
    grid->addWidget(m_topStepLabel, 2, 0, 1, 1);
15✔
120

121
    m_sideFader = new ClickAndGoSlider();
15✔
122
    m_sideFader->setSliderStyleSheet(CNG_DEFAULT_STYLE);
15✔
123
    m_sideFader->setFixedWidth(32);
15✔
124
    m_sideFader->setRange(0, 100);
15✔
125
    m_sideFader->setValue(100);
15✔
126
    grid->addWidget(m_sideFader, 3, 0, 1, 1);
15✔
127

128
    m_bottomStepLabel = new QLabel("");
15✔
129
    m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
15✔
130
    m_bottomStepLabel->setAlignment(Qt::AlignCenter);
15✔
131
    m_bottomStepLabel->setFixedSize(32, 24);
15✔
132
    grid->addWidget(m_bottomStepLabel, 4, 0, 1, 1);
15✔
133

134
    m_bottomPercentageLabel = new QLabel("0%");
15✔
135
    m_bottomPercentageLabel->setAlignment(Qt::AlignHCenter);
15✔
136
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
137
    m_bottomPercentageLabel->setFixedWidth(m_fm.width("100%"));
138
#else
139
    m_bottomPercentageLabel->setFixedWidth(m_fm.horizontalAdvance("100%"));
15✔
140
#endif
141
    grid->addWidget(m_bottomPercentageLabel, 5, 0, 1, 1);
15✔
142

143
    connect(m_sideFader, SIGNAL(valueChanged(int)),
15✔
144
            this, SLOT(slotSideFaderValueChanged(int)));
145

146
    slotShowCrossfadePanel(false);
15✔
147

148
    QVBoxLayout *vbox = new QVBoxLayout();
15✔
149

150
    /* Create a list for scenes (cues) */
151
    m_tree = new QTreeWidget(this);
15✔
152
    m_tree->setSelectionMode(QAbstractItemView::SingleSelection);
15✔
153
    //m_tree->setAlternatingRowColors(true);
154
    m_tree->setAllColumnsShowFocus(true);
15✔
155
    m_tree->setRootIsDecorated(false);
15✔
156
    m_tree->setItemsExpandable(false);
15✔
157
    m_tree->header()->setSortIndicatorShown(false);
15✔
158
    m_tree->header()->setMinimumSectionSize(0); // allow columns to be hidden
15✔
159
    m_tree->header()->setSectionsClickable(false);
15✔
160
    m_tree->header()->setSectionsMovable(false);
15✔
161

162
    // Make only the notes column editable
163
    m_tree->setItemDelegateForColumn(COL_NUM, new NoEditDelegate(this));
15✔
164
    m_tree->setItemDelegateForColumn(COL_NAME, new NoEditDelegate(this));
15✔
165
    m_tree->setItemDelegateForColumn(COL_FADEIN, new NoEditDelegate(this));
15✔
166
    m_tree->setItemDelegateForColumn(COL_FADEOUT, new NoEditDelegate(this));
15✔
167
    m_tree->setItemDelegateForColumn(COL_DURATION, new NoEditDelegate(this));
15✔
168

169
    connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
15✔
170
            this, SLOT(slotItemActivated(QTreeWidgetItem*)));
171
    connect(m_tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
15✔
172
            this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
173
    vbox->addWidget(m_tree);
15✔
174

175
    m_progress = new QProgressBar(this);
15✔
176
    m_progress->setOrientation(Qt::Horizontal);
15✔
177
    m_progress->setStyleSheet(progressDisabledStyle);
15✔
178
    m_progress->setProperty("status", 0);
15✔
179
    m_progress->setFixedHeight(20);
15✔
180
    vbox->addWidget(m_progress);
15✔
181

182
    m_timer = new QTimer(this);
15✔
183
    connect(m_timer, SIGNAL(timeout()),
15✔
184
            this, SLOT(slotProgressTimeout()));
185

186
    m_updateTimer = new QTimer(this);
15✔
187
    connect(m_updateTimer, SIGNAL(timeout()),
15✔
188
            this, SLOT(slotUpdateStepList()));
189
    m_updateTimer->setSingleShot(true);
15✔
190

191
    /* Create control buttons */
192
    QHBoxLayout *hbox = new QHBoxLayout();
15✔
193
    hbox->setSpacing(2);
15✔
194

195
    m_crossfadeButton = new QToolButton(this);
15✔
196
    m_crossfadeButton->setIcon(QIcon(":/slider.png"));
15✔
197
    m_crossfadeButton->setIconSize(QSize(24, 24));
15✔
198
    m_crossfadeButton->setCheckable(true);
15✔
199
    m_crossfadeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
15✔
200
    m_crossfadeButton->setFixedHeight(32);
15✔
201
    m_crossfadeButton->setToolTip(tr("Show/Hide crossfade sliders"));
15✔
202
    m_crossfadeButton->setVisible(false);
15✔
203
    connect(m_crossfadeButton, SIGNAL(toggled(bool)),
15✔
204
            this, SLOT(slotShowCrossfadePanel(bool)));
205
    hbox->addWidget(m_crossfadeButton);
15✔
206

207
    m_playbackButton = new QToolButton(this);
15✔
208
    m_playbackButton->setIcon(QIcon(":/player_play.png"));
15✔
209
    m_playbackButton->setIconSize(QSize(24, 24));
15✔
210
    m_playbackButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
15✔
211
    m_playbackButton->setFixedHeight(32);
15✔
212
    m_playbackButton->setToolTip(tr("Play/Pause Cue list"));
15✔
213
    connect(m_playbackButton, SIGNAL(clicked()), this, SLOT(slotPlayback()));
15✔
214
    hbox->addWidget(m_playbackButton);
15✔
215

216
    m_stopButton = new QToolButton(this);
15✔
217
    m_stopButton->setIcon(QIcon(":/player_stop.png"));
15✔
218
    m_stopButton->setIconSize(QSize(24, 24));
15✔
219
    m_stopButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
15✔
220
    m_stopButton->setFixedHeight(32);
15✔
221
    m_stopButton->setToolTip(tr("Stop Cue list"));
15✔
222
    connect(m_stopButton, SIGNAL(clicked()), this, SLOT(slotStop()));
15✔
223
    hbox->addWidget(m_stopButton);
15✔
224

225
    m_previousButton = new QToolButton(this);
15✔
226
    m_previousButton->setIcon(QIcon(":/back.png"));
15✔
227
    m_previousButton->setIconSize(QSize(24, 24));
15✔
228
    m_previousButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
15✔
229
    m_previousButton->setFixedHeight(32);
15✔
230
    m_previousButton->setToolTip(tr("Go to previous step in the list"));
15✔
231
    connect(m_previousButton, SIGNAL(clicked()), this, SLOT(slotPreviousCue()));
15✔
232
    hbox->addWidget(m_previousButton);
15✔
233

234
    m_nextButton = new QToolButton(this);
15✔
235
    m_nextButton->setIcon(QIcon(":/forward.png"));
15✔
236
    m_nextButton->setIconSize(QSize(24, 24));
15✔
237
    m_nextButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
15✔
238
    m_nextButton->setFixedHeight(32);
15✔
239
    m_nextButton->setToolTip(tr("Go to next step in the list"));
15✔
240
    connect(m_nextButton, SIGNAL(clicked()), this, SLOT(slotNextCue()));
15✔
241
    hbox->addWidget(m_nextButton);
15✔
242

243
    vbox->addItem(hbox);
15✔
244
    grid->addItem(vbox, 0, 1, 6);
15✔
245

246
    setFrameStyle(KVCFrameStyleSunken);
15✔
247
    setType(VCWidget::CueListWidget);
15✔
248
    setCaption(tr("Cue list"));
15✔
249

250
    QSettings settings;
30✔
251
    QVariant var = settings.value(SETTINGS_CUELIST_SIZE);
30✔
252
    if (var.isValid() == true)
15✔
253
        resize(var.toSize());
×
254
    else
255
        resize(QSize(300, 220));
15✔
256

257
    slotModeChanged(m_doc->mode());
15✔
258
    setLiveEdit(m_liveEdit);
15✔
259

260
    connect(m_doc, SIGNAL(functionRemoved(quint32)),
15✔
261
            this, SLOT(slotFunctionRemoved(quint32)));
262
    connect(m_doc, SIGNAL(functionChanged(quint32)),
15✔
263
            this, SLOT(slotFunctionChanged(quint32)));
264
    connect(m_doc, SIGNAL(functionNameChanged(quint32)),
15✔
265
            this, SLOT(slotFunctionNameChanged(quint32)));
266

267
    m_nextLatestValue = 0;
15✔
268
    m_previousLatestValue = 0;
15✔
269
    m_playbackLatestValue = 0;
15✔
270
    m_stopLatestValue = 0;
15✔
271
}
15✔
272

273
VCCueList::~VCCueList()
17✔
274
{
275
}
17✔
276

277
void VCCueList::enableWidgetUI(bool enable)
23✔
278
{
279
    m_tree->setEnabled(enable);
23✔
280
    m_playbackButton->setEnabled(enable);
23✔
281
    m_stopButton->setEnabled(enable);
23✔
282
    m_previousButton->setEnabled(enable);
23✔
283
    m_nextButton->setEnabled(enable);
23✔
284

285
    m_topPercentageLabel->setEnabled(enable);
23✔
286
    m_sideFader->setEnabled(enable);
23✔
287
    m_topStepLabel->setEnabled(enable);
23✔
288
    m_bottomPercentageLabel->setEnabled(enable);
23✔
289
    m_bottomStepLabel->setEnabled(enable);
23✔
290
}
23✔
291

292
/*****************************************************************************
293
 * Clipboard
294
 *****************************************************************************/
295

296
VCWidget *VCCueList::createCopy(VCWidget *parent)
1✔
297
{
298
    Q_ASSERT(parent != NULL);
1✔
299

300
    VCCueList *cuelist = new VCCueList(parent, m_doc);
1✔
301
    if (cuelist->copyFrom(this) == false)
1✔
302
    {
303
        delete cuelist;
×
304
        cuelist = NULL;
×
305
    }
306

307
    return cuelist;
1✔
308
}
309

310
bool VCCueList::copyFrom(const VCWidget *widget)
3✔
311
{
312
    const VCCueList *cuelist = qobject_cast<const VCCueList*> (widget);
3✔
313
    if (cuelist == NULL)
3✔
314
        return false;
1✔
315

316
    /* Function list contents */
317
    setChaser(cuelist->chaserID());
2✔
318

319
    /* Key sequence */
320
    setNextKeySequence(cuelist->nextKeySequence());
2✔
321
    setPreviousKeySequence(cuelist->previousKeySequence());
2✔
322
    setPlaybackKeySequence(cuelist->playbackKeySequence());
2✔
323
    setStopKeySequence(cuelist->stopKeySequence());
2✔
324

325
    /* Sliders mode */
326
    setSideFaderMode(cuelist->sideFaderMode());
2✔
327

328
    /* Common stuff */
329
    return VCWidget::copyFrom(widget);
2✔
330
}
331

332
/*****************************************************************************
333
 * Cue list
334
 *****************************************************************************/
335

336
void VCCueList::setChaser(quint32 id)
14✔
337
{
338
    Function *old = m_doc->function(m_chaserID);
14✔
339
    if (old != NULL)
14✔
340
    {
341
        /* Get rid of old function connections */
342
        disconnect(old, SIGNAL(running(quint32)),
1✔
343
                this, SLOT(slotFunctionRunning(quint32)));
344
        disconnect(old, SIGNAL(stopped(quint32)),
1✔
345
                this, SLOT(slotFunctionStopped(quint32)));
346
        disconnect(old, SIGNAL(currentStepChanged(int)),
1✔
347
                this, SLOT(slotCurrentStepChanged(int)));
348
    }
349

350
    Chaser *chaser = qobject_cast<Chaser*> (m_doc->function(id));
14✔
351
    if (chaser != NULL)
14✔
352
    {
353
        /* Connect to the new function */
354
        connect(chaser, SIGNAL(running(quint32)),
11✔
355
                this, SLOT(slotFunctionRunning(quint32)));
356
        connect(chaser, SIGNAL(stopped(quint32)),
11✔
357
                this, SLOT(slotFunctionStopped(quint32)));
358
        connect(chaser, SIGNAL(currentStepChanged(int)),
11✔
359
                this, SLOT(slotCurrentStepChanged(int)));
360

361
        m_chaserID = id;
11✔
362
    }
363
    else
364
    {
365
        m_chaserID = Function::invalidId();
3✔
366
    }
367

368
    updateStepList();
14✔
369

370
    /* Current status */
371
    if (chaser != NULL && chaser->isRunning())
14✔
372
    {
373
        slotFunctionRunning(m_chaserID);
×
374
        slotCurrentStepChanged(chaser->currentStepIndex());
×
375
    }
376
    else
377
        slotFunctionStopped(m_chaserID);
14✔
378
}
14✔
379

380
quint32 VCCueList::chaserID() const
9✔
381
{
382
    return m_chaserID;
9✔
383
}
384

385
Chaser *VCCueList::chaser()
88✔
386
{
387
    if (m_chaserID == Function::invalidId())
88✔
388
        return NULL;
6✔
389
    Chaser *chaser = qobject_cast<Chaser*>(m_doc->function(m_chaserID));
82✔
390
    return chaser;
82✔
391
}
392

393
void VCCueList::updateStepList()
15✔
394
{
395
    m_listIsUpdating = true;
15✔
396

397
    m_tree->clear();
15✔
398

399
    Chaser *ch = chaser();
15✔
400
    if (ch == NULL)
15✔
401
        return;
3✔
402

403
    QListIterator <ChaserStep> it(ch->steps());
24✔
404
    while (it.hasNext() == true)
59✔
405
    {
406
        ChaserStep step(it.next());
94✔
407

408
        Function *function = m_doc->function(step.fid);
47✔
409
        Q_ASSERT(function != NULL);
47✔
410

411
        QTreeWidgetItem *item = new QTreeWidgetItem(m_tree);
47✔
412
        item->setFlags(item->flags() | Qt::ItemIsEditable);
47✔
413
        int index = m_tree->indexOfTopLevelItem(item) + 1;
47✔
414
        item->setText(COL_NUM, QString("%1").arg(index));
47✔
415
        item->setData(COL_NUM, PROP_ID, function->id());
47✔
416
        item->setText(COL_NAME, function->name());
47✔
417
        if (step.note.isEmpty() == false)
47✔
418
            item->setText(COL_NOTES, step.note);
×
419

420
        switch (ch->fadeInMode())
47✔
421
        {
422
            case Chaser::Common:
×
423
                item->setText(COL_FADEIN, Function::speedToString(ch->fadeInSpeed()));
×
424
                break;
×
425
            case Chaser::PerStep:
×
426
                item->setText(COL_FADEIN, Function::speedToString(step.fadeIn));
×
427
                break;
×
428
            default:
47✔
429
            case Chaser::Default:
430
                item->setText(COL_FADEIN, QString());
47✔
431
        }
432

433
        switch (ch->fadeOutMode())
47✔
434
        {
435
            case Chaser::Common:
×
436
                item->setText(COL_FADEOUT, Function::speedToString(ch->fadeOutSpeed()));
×
437
                break;
×
438
            case Chaser::PerStep:
×
439
                item->setText(COL_FADEOUT, Function::speedToString(step.fadeOut));
×
440
                break;
×
441
            default:
47✔
442
            case Chaser::Default:
443
                item->setText(COL_FADEOUT, QString());
47✔
444
        }
445

446
        switch (ch->durationMode())
47✔
447
        {
448
            case Chaser::Common:
47✔
449
                item->setText(COL_DURATION, Function::speedToString(ch->duration()));
47✔
450
                break;
47✔
451
            case Chaser::PerStep:
×
452
                item->setText(COL_DURATION, Function::speedToString(step.duration));
×
453
                break;
×
454
            default:
×
455
            case Chaser::Default:
456
                item->setText(COL_DURATION, QString());
×
457
        }
458
    }
459

460
    QTreeWidgetItem *item = m_tree->topLevelItem(0);
12✔
461
    if (item != NULL)
12✔
462
        m_defCol = item->background(COL_NUM);
12✔
463

464
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
12✔
465
    m_tree->header()->setSectionHidden(COL_NAME, ch->type() == Function::SequenceType ? true : false);
12✔
466
    m_listIsUpdating = false;
12✔
467
}
468

469
int VCCueList::getCurrentIndex()
×
470
{
471
    int index = m_tree->indexOfTopLevelItem(m_tree->currentItem());
×
472
    if (index == -1)
×
473
        index = 0;
×
474
    return index;
×
475
}
476

477
int VCCueList::getNextIndex()
×
478
{
479
    Chaser *ch = chaser();
×
480
    if (ch == NULL)
×
481
        return -1;
×
482

483
    if (ch->direction() == Function::Forward)
×
484
        return getNextTreeIndex();
×
485
    else
486
        return getPrevTreeIndex();
×
487
}
488

489
int VCCueList::getPrevIndex()
×
490
{
491
    Chaser *ch = chaser();
×
492
    if (ch == NULL)
×
493
        return -1;
×
494

495
    if (ch->direction() == Function::Forward)
×
496
        return getPrevTreeIndex();
×
497
    else
498
        return getNextTreeIndex();
×
499
}
500

501
int VCCueList::getFirstIndex()
3✔
502
{
503
    Chaser *ch = chaser();
3✔
504
    if (ch == NULL)
3✔
505
        return -1;
×
506

507
    if (ch->direction() == Function::Forward)
3✔
508
        return getFirstTreeIndex();
3✔
509
    else
510
        return getLastTreeIndex();
×
511
}
512

513
int VCCueList::getLastIndex()
×
514
{
515
    Chaser *ch = chaser();
×
516
    if (ch == NULL)
×
517
        return -1;
×
518

519
    if (ch->direction() == Function::Forward)
×
520
        return getLastTreeIndex();
×
521
    else
522
        return getFirstTreeIndex();
×
523
}
524

525
int VCCueList::getNextTreeIndex()
×
526
{
527
    int count = m_tree->topLevelItemCount();
×
528
    if (count > 0)
×
529
        return (getCurrentIndex() + 1) % count;
×
530
    return 0;
×
531
}
532

533
int VCCueList::getPrevTreeIndex()
×
534
{
535
    int currentIndex = getCurrentIndex();
×
536
    if (currentIndex <= 0)
×
537
        return getLastTreeIndex();
×
538
    return currentIndex - 1;
×
539
}
540

541
int VCCueList::getFirstTreeIndex()
3✔
542
{
543
    return 0;
3✔
544
}
545

546
int VCCueList::getLastTreeIndex()
×
547
{
548
    return m_tree->topLevelItemCount() - 1;
×
549
}
550

551
qreal VCCueList::getPrimaryIntensity() const
20✔
552
{
553
    if (sideFaderMode() == Steps)
20✔
554
        return  1.0;
×
555

556
    return m_primaryTop ? qreal(m_sideFader->value() / 100.0) : qreal((100 - m_sideFader->value()) / 100.0);
20✔
557
}
558

559
void VCCueList::notifyFunctionStarting(quint32 fid, qreal intensity)
×
560
{
561
    Q_UNUSED(intensity);
562

563
    if (mode() == Doc::Design)
×
564
        return;
×
565

566
    if (fid == m_chaserID)
×
567
        return;
×
568

569
    stopChaser();
×
570
}
571

572
void VCCueList::slotFunctionRemoved(quint32 fid)
2✔
573
{
574
    if (fid == m_chaserID)
2✔
575
    {
576
        setChaser(Function::invalidId());
1✔
577
        resetIntensityOverrideAttribute();
1✔
578
    }
579
}
2✔
580

581
void VCCueList::slotFunctionChanged(quint32 fid)
5✔
582
{
583
    if (fid == m_chaserID && !m_updateTimer->isActive())
5✔
584
        m_updateTimer->start(UPDATE_TIMEOUT);
1✔
585
}
5✔
586

587
void VCCueList::slotFunctionNameChanged(quint32 fid)
×
588
{
589
    if (fid == m_chaserID)
×
590
        m_updateTimer->start(UPDATE_TIMEOUT);
×
591
    else
592
    {
593
        // fid might be an ID of a ChaserStep of m_chaser
594
        Chaser *ch = chaser();
×
595
        if (ch == NULL)
×
596
            return;
×
597
        foreach (ChaserStep step, ch->steps())
×
598
        {
599
            if (step.fid == fid)
×
600
            {
601
                m_updateTimer->start(UPDATE_TIMEOUT);
×
602
                return;
×
603
            }
604
        }
605
    }
606
}
607

608
void VCCueList::slotUpdateStepList()
1✔
609
{
610
    updateStepList();
1✔
611
}
1✔
612

613
void VCCueList::slotPlayback()
2✔
614
{
615
    if (mode() != Doc::Operate)
2✔
616
        return;
×
617

618
    Chaser *ch = chaser();
2✔
619
    if (ch == NULL)
2✔
620
        return;
×
621

622
    if (ch->isRunning())
2✔
623
    {
624
        if (playbackLayout() == PlayPauseStop)
2✔
625
        {
626
            if (ch->isPaused())
2✔
627
            {
628
                m_playbackButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
629
                                                .arg(m_stopButton->palette().window().color().name()));
×
630
                m_playbackButton->setIcon(QIcon(":/player_pause.png"));
×
631
            }
632
            else
633
            {
634
                m_playbackButton->setStyleSheet("QToolButton{ background: #5B81FF; }");
2✔
635
                m_playbackButton->setIcon(QIcon(":/player_play.png"));
2✔
636
            }
637

638
            // check if the item selection has been changed during pause
639
            int currentTreeIndex = m_tree->indexOfTopLevelItem(m_tree->currentItem());
2✔
640
            if (currentTreeIndex != ch->currentStepIndex())
2✔
641
                playCueAtIndex(currentTreeIndex);
×
642

643
            ch->setPause(!ch->isPaused());
2✔
644
        }
645
        else if (playbackLayout() == PlayStopPause)
×
646
        {
647
            stopChaser();
×
648
            m_stopButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
649
                                            .arg(m_playbackButton->palette().window().color().name()));
×
650
        }
651
    }
652
    else
653
    {
654
        if (m_tree->currentItem() != NULL)
×
655
            startChaser(getCurrentIndex());
×
656
        else
657
            startChaser();
×
658
    }
659

660
    emit playbackButtonClicked();
2✔
661
}
662

663
void VCCueList::slotStop()
×
664
{
665
    if (mode() != Doc::Operate)
×
666
        return;
×
667

668
    Chaser *ch = chaser();
×
669
    if (ch == NULL)
×
670
        return;
×
671

672
    if (ch->isRunning())
×
673
    {
674
        if (playbackLayout() == PlayPauseStop)
×
675
        {
676
            stopChaser();
×
677
            m_playbackButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
678
                                            .arg(m_stopButton->palette().window().color().name()));
×
679
            m_progress->setFormat("");
×
680
            m_progress->setValue(0);
×
681

682
            emit progressStateChanged();
×
683
        }
684
        else if (playbackLayout() == PlayStopPause)
×
685
        {
686
            if (ch->isPaused())
×
687
            {
688
                m_stopButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
689
                                                .arg(m_playbackButton->palette().window().color().name()));
×
690
                m_stopButton->setIcon(QIcon(":/player_pause.png"));
×
691
            }
692
            else
693
            {
694
                m_stopButton->setStyleSheet("QToolButton{ background: #5B81FF; }");
×
695
            }
696
            ch->setPause(!ch->isPaused());
×
697
        }
698
    }
699
    else
700
    {
701
        m_primaryIndex = 0;
×
702
        m_tree->setCurrentItem(m_tree->topLevelItem(getFirstIndex()));
×
703
    }
704

705
    emit stopButtonClicked();
×
706
}
707

708
void VCCueList::slotNextCue()
10✔
709
{
710
    if (mode() != Doc::Operate)
10✔
711
        return;
1✔
712

713
    Chaser *ch = chaser();
9✔
714
    if (ch == NULL)
9✔
715
        return;
×
716

717
    if (ch->isRunning())
9✔
718
    {
719
        if (ch->isPaused())
6✔
720
        {
721
            m_tree->setCurrentItem(m_tree->topLevelItem(getNextIndex()));
×
722
        }
723
        else
724
        {
725
            ChaserAction action;
726
            action.m_action = ChaserNextStep;
6✔
727
            action.m_masterIntensity = intensity();
6✔
728
            action.m_stepIntensity = getPrimaryIntensity();
6✔
729
            action.m_fadeMode = getFadeMode();
6✔
730
            ch->setAction(action);
6✔
731
        }
732
    }
733
    else
734
    {
735
        switch (m_nextPrevBehavior)
3✔
736
        {
737
            case DefaultRunFirst:
3✔
738
                startChaser(getFirstIndex());
3✔
739
            break;
3✔
740
            case RunNext:
×
741
                startChaser(getNextIndex());
×
742
            break;
×
743
            case Select:
×
744
                m_tree->setCurrentItem(m_tree->topLevelItem(getNextIndex()));
×
745
            break;
×
746
            case Nothing:
×
747
            break;
×
748
            default:
×
749
                Q_ASSERT(false);
×
750
        }
751
    }
752
}
753

754
void VCCueList::slotPreviousCue()
8✔
755
{
756
    if (mode() != Doc::Operate)
8✔
757
        return;
1✔
758

759
    Chaser *ch = chaser();
7✔
760
    if (ch == NULL)
7✔
761
        return;
×
762

763
    if (ch->isRunning())
7✔
764
    {
765
        if (ch->isPaused())
7✔
766
        {
767
            m_tree->setCurrentItem(m_tree->topLevelItem(getPrevIndex()));
×
768
        }
769
        else
770
        {
771
            ChaserAction action;
772
            action.m_action = ChaserPreviousStep;
7✔
773
            action.m_masterIntensity = intensity();
7✔
774
            action.m_stepIntensity = getPrimaryIntensity();
7✔
775
            action.m_fadeMode = getFadeMode();
7✔
776
            ch->setAction(action);
7✔
777
        }
778
    }
779
    else
780
    {
781
        switch (m_nextPrevBehavior)
×
782
        {
783
            case DefaultRunFirst:
×
784
                startChaser(getLastIndex());
×
785
            break;
×
786
            case RunNext:
×
787
                startChaser(getPrevIndex());
×
788
            break;
×
789
            case Select:
×
790
                m_tree->setCurrentItem(m_tree->topLevelItem(getPrevIndex()));
×
791
            break;
×
792
            case Nothing:
×
793
            break;
×
794
            default:
×
795
                Q_ASSERT(false);
×
796
        }
797
    }
798
}
799

800
void VCCueList::slotCurrentStepChanged(int stepNumber)
19✔
801
{
802
    // Chaser is being edited, channels count may change.
803
    // Wait for the CueList to update its steps.
804
    if (m_updateTimer->isActive())
19✔
805
        return;
×
806

807
    Q_ASSERT(stepNumber < m_tree->topLevelItemCount() && stepNumber >= 0);
19✔
808
    QTreeWidgetItem *item = m_tree->topLevelItem(stepNumber);
19✔
809
    Q_ASSERT(item != NULL);
19✔
810
    m_tree->scrollToItem(item, QAbstractItemView::PositionAtCenter);
19✔
811
    m_tree->setCurrentItem(item);
19✔
812
    m_primaryIndex = stepNumber;
19✔
813
    if (sideFaderMode() == Steps)
19✔
814
    {
815
        m_bottomStepLabel->setStyleSheet(cfLabelBlueStyle);
×
816
        m_bottomStepLabel->setText(QString("#%1").arg(m_primaryIndex + 1));
×
817

818
        float stepVal;
819
        int stepsCount = m_tree->topLevelItemCount();
×
820
        if (stepsCount < 256)
×
821
            stepVal = 255.0 / (float)stepsCount;
×
822
        else
823
            stepVal = 1.0;
×
824
        int slValue = (stepVal * (float)stepNumber);
×
825
        if (slValue > 255)
×
826
            slValue = 255;
×
827

828
        int upperBound = 255 - slValue;
×
829
        int lowerBound = qFloor(upperBound - stepVal);
×
830
        //qDebug() << "Slider value:" << m_slider1->value() << "Step range:" << (255 - slValue) << (255 - slValue - stepVal);
831
        // if the Step slider is already in range, then do not set its value
832
        // this means a user interaction is going on, either with the mouse or external controller
833
        if (m_sideFader->value() < lowerBound || m_sideFader->value() >= upperBound)
×
834
        {
835
            m_sideFader->blockSignals(true);
×
836
            m_sideFader->setValue(upperBound);
×
837
            m_topPercentageLabel->setText(QString("%1").arg(slValue));
×
838
            m_sideFader->blockSignals(false);
×
839
        }
840
    }
841
    else
842
    {
843
        setFaderInfo(m_primaryIndex);
19✔
844
    }
845
    emit stepChanged(m_primaryIndex);
19✔
846
    emit sideFaderValueChanged();
19✔
847
}
848

849
void VCCueList::slotItemActivated(QTreeWidgetItem *item)
5✔
850
{
851
    if (mode() != Doc::Operate)
5✔
852
        return;
1✔
853

854
    playCueAtIndex(m_tree->indexOfTopLevelItem(item));
4✔
855
}
856

857
void VCCueList::slotItemChanged(QTreeWidgetItem *item, int column)
374✔
858
{
859
    if (m_listIsUpdating || column != COL_NOTES)
374✔
860
        return;
374✔
861

862
    Chaser *ch = chaser();
×
863
    if (ch == NULL)
×
864
        return;
×
865

866
    QString itemText = item->text(column);
×
867
    int idx = m_tree->indexOfTopLevelItem(item);
×
868
    ChaserStep step = ch->steps().at(idx);
×
869

870
    step.note = itemText;
×
871
    ch->replaceStep(step, idx);
×
872
}
873

874
void VCCueList::slotFunctionRunning(quint32 fid)
4✔
875
{
876
    if (fid != m_chaserID)
4✔
877
        return;
×
878

879
    if (playbackLayout() == PlayPauseStop)
4✔
880
        m_playbackButton->setIcon(QIcon(":/player_pause.png"));
4✔
881
    else if (playbackLayout() == PlayStopPause)
×
882
        m_playbackButton->setIcon(QIcon(":/player_stop.png"));
×
883
    m_timer->start(PROGRESS_INTERVAL);
4✔
884
    emit playbackStatusChanged();
4✔
885
    updateFeedback();
4✔
886
}
887

888
void VCCueList::slotFunctionStopped(quint32 fid)
14✔
889
{
890
    if (fid != m_chaserID)
14✔
891
        return;
×
892

893
    m_playbackButton->setIcon(QIcon(":/player_play.png"));
14✔
894
    m_topStepLabel->setText("");
14✔
895
    m_topStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
896
    m_bottomStepLabel->setText("");
14✔
897
    m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
898
    // reset any previously set background
899
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
14✔
900
    if (item != NULL)
14✔
901
        item->setBackground(COL_NUM, m_defCol);
11✔
902

903
    emit stepChanged(-1);
14✔
904

905
    m_progress->setFormat("");
14✔
906
    m_progress->setValue(0);    
14✔
907

908
    emit progressStateChanged();
14✔
909
    emit sideFaderValueChanged();
14✔
910
    emit playbackStatusChanged();
14✔
911

912
    qDebug() << Q_FUNC_INFO << "Cue stopped";
14✔
913
    updateFeedback();
14✔
914
}
915

916
void VCCueList::slotProgressTimeout()
×
917
{
918
    Chaser *ch = chaser();
×
919
    if (ch == NULL || !ch->isRunning())
×
920
        return;
×
921

922
    ChaserRunnerStep step(ch->currentRunningStep());
×
923
    if (step.m_function != NULL)
×
924
    {
925
        int status = m_progress->property("status").toInt();
×
926
        int newstatus;
927
        if (step.m_fadeIn == Function::defaultSpeed())
×
928
            newstatus = 1;
×
929
        else if (step.m_elapsed > (quint32)step.m_fadeIn)
×
930
            newstatus = 1;
×
931
        else
932
            newstatus = 0;
×
933

934
        if (newstatus != status)
×
935
        {
936
            if (newstatus == 0)
×
937
                m_progress->setStyleSheet(progressFadeStyle);
×
938
            else
939
                m_progress->setStyleSheet(progressHoldStyle);
×
940
            m_progress->setProperty("status", newstatus);
×
941
        }
942
        if (step.m_duration == Function::infiniteSpeed())
×
943
        {
944
            if (newstatus == 0 && step.m_fadeIn != Function::defaultSpeed())
×
945
            {
946
                double progress = ((double)step.m_elapsed / (double)step.m_fadeIn) * (double)m_progress->width();
×
947
                m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_fadeIn - step.m_elapsed)));
×
948
                m_progress->setValue(progress);
×
949

950
                emit progressStateChanged();
×
951
            }
952
            else
953
            {
954
                m_progress->setValue(m_progress->maximum());
×
955
                m_progress->setFormat("");
×
956

957
                emit progressStateChanged();
×
958
            }
959
            return;
×
960
        }
961
        else
962
        {
963
            double progress = ((double)step.m_elapsed / (double)step.m_duration) * (double)m_progress->width();
×
964
            m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_duration - step.m_elapsed)));
×
965
            m_progress->setValue(progress);
×
966

967
            emit progressStateChanged();
×
968
        }
969
    }
970
    else
971
    {
972
        m_progress->setValue(0);
×
973
    }
974
}
975

976
QString VCCueList::progressText()
×
977
{
978
    return m_progress->text();
×
979
}
980

981
double VCCueList::progressPercent()
×
982
{
983
    return ((double)m_progress->value() * 100) / (double)m_progress->width();
×
984
}
985

986
void VCCueList::startChaser(int startIndex)
4✔
987
{
988
    Chaser *ch = chaser();
4✔
989
    if (ch == NULL)
4✔
990
        return;
×
991

992
    adjustFunctionIntensity(ch, intensity());
4✔
993

994
    ChaserAction action;
995
    action.m_action = ChaserSetStepIndex;
4✔
996
    action.m_stepIndex = startIndex;
4✔
997
    action.m_masterIntensity = intensity();
4✔
998
    action.m_stepIntensity = getPrimaryIntensity();
4✔
999
    action.m_fadeMode = getFadeMode();
4✔
1000
    ch->setAction(action);
4✔
1001

1002
    ch->start(m_doc->masterTimer(), functionParent());
4✔
1003
    emit functionStarting(m_chaserID);
4✔
1004
}
1005

1006
void VCCueList::stopChaser()
×
1007
{
1008
    Chaser *ch = chaser();
×
1009
    if (ch == NULL)
×
1010
        return;
×
1011

1012
    ch->stop(functionParent());
×
1013
    resetIntensityOverrideAttribute();
×
1014
}
1015

1016
int VCCueList::getFadeMode()
20✔
1017
{
1018
    if (sideFaderMode() != Crossfade)
20✔
1019
        return Chaser::FromFunction;
20✔
1020

1021
    if (m_sideFader->value() != 0 && m_sideFader->value() != 100)
×
1022
        return Chaser::BlendedCrossfade;
×
1023

1024
    return Chaser::Blended;
×
1025
}
1026

1027
void VCCueList::setNextPrevBehavior(NextPrevBehavior nextPrev)
×
1028
{
1029
    Q_ASSERT(nextPrev == DefaultRunFirst
×
1030
            || nextPrev == RunNext
1031
            || nextPrev == Select
1032
            || nextPrev == Nothing);
1033
    m_nextPrevBehavior = nextPrev;
×
1034
}
×
1035

1036
VCCueList::NextPrevBehavior VCCueList::nextPrevBehavior() const
1✔
1037
{
1038
    return m_nextPrevBehavior;
1✔
1039
}
1040

1041
void VCCueList::setPlaybackLayout(VCCueList::PlaybackLayout layout)
×
1042
{
1043
    if (layout == m_playbackLayout)
×
1044
        return;
×
1045

1046
    if (layout == PlayStopPause)
×
1047
    {
1048
        m_stopButton->setIcon(QIcon(":/player_pause.png"));
×
1049
        m_playbackButton->setToolTip(tr("Play/Stop Cue list"));
×
1050
        m_stopButton->setToolTip(tr("Pause Cue list"));
×
1051
    }
1052
    else if (layout == PlayPauseStop)
×
1053
    {
1054
        m_stopButton->setIcon(QIcon(":/player_stop.png"));
×
1055
        m_playbackButton->setToolTip(tr("Play/Pause Cue list"));
×
1056
        m_stopButton->setToolTip(tr("Stop Cue list"));
×
1057
    }
1058
    else
1059
    {
1060
        qWarning() << "Playback layout" << layout << "doesn't exist!";
×
1061
        layout = PlayPauseStop;
×
1062
    }
1063

1064
    m_playbackLayout = layout;
×
1065
}
1066

1067
VCCueList::PlaybackLayout VCCueList::playbackLayout() const
7✔
1068
{
1069
    return m_playbackLayout;
7✔
1070
}
1071

1072
VCCueList::FaderMode VCCueList::sideFaderMode() const
67✔
1073
{
1074
    return m_slidersMode;
67✔
1075
}
1076

1077
void VCCueList::setSideFaderMode(VCCueList::FaderMode mode)
3✔
1078
{
1079
    m_slidersMode = mode;
3✔
1080

1081
    bool show = (mode == None) ? false : true;
3✔
1082
    m_crossfadeButton->setVisible(show);
3✔
1083
    m_topPercentageLabel->setVisible(show);
3✔
1084
    m_topStepLabel->setVisible(mode == Steps ? false : show);
3✔
1085
    m_sideFader->setVisible(show);
3✔
1086
    m_bottomPercentageLabel->setVisible(mode == Steps ? false : show);
3✔
1087
    m_bottomStepLabel->setVisible(show);
3✔
1088
    m_sideFader->setMaximum(mode == Steps ? 255 : 100);
3✔
1089
    m_sideFader->setValue(mode == Steps ? 255 : 100);
3✔
1090
}
3✔
1091

1092
VCCueList::FaderMode VCCueList::stringToFaderMode(QString modeStr)
×
1093
{
1094
    if (modeStr == "Crossfade")
×
1095
        return Crossfade;
×
1096
    else if (modeStr == "Steps")
×
1097
        return Steps;
×
1098

1099
    return None;
×
1100
}
1101

1102
QString VCCueList::faderModeToString(VCCueList::FaderMode mode)
1✔
1103
{
1104
    if (mode == Crossfade)
1✔
1105
        return "Crossfade";
1✔
1106
    else if (mode == Steps)
×
1107
        return "Steps";
×
1108

1109
    return "None";
×
1110
}
1111

1112
/*****************************************************************************
1113
 * Crossfade
1114
 *****************************************************************************/
1115
void VCCueList::setFaderInfo(int index)
19✔
1116
{
1117
    Chaser *ch = chaser();
19✔
1118
    if (ch == NULL || !ch->isRunning())
19✔
1119
        return;
×
1120

1121
    int tmpIndex = ch->computeNextStep(index);
19✔
1122

1123
    m_topStepLabel->setText(QString("#%1").arg(m_primaryTop ? index + 1 : tmpIndex + 1));
19✔
1124
    m_topStepLabel->setStyleSheet(m_primaryTop ? cfLabelBlueStyle : cfLabelOrangeStyle);
19✔
1125

1126
    m_bottomStepLabel->setText(QString("#%1").arg(m_primaryTop ? tmpIndex + 1 : index + 1));
19✔
1127
    m_bottomStepLabel->setStyleSheet(m_primaryTop ? cfLabelOrangeStyle : cfLabelBlueStyle);
19✔
1128

1129
    // reset any previously set background
1130
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
19✔
1131
    if (item != NULL)
19✔
1132
        item->setBackground(COL_NUM, m_defCol);
19✔
1133

1134
    item = m_tree->topLevelItem(tmpIndex);
19✔
1135
    if (item != NULL)
19✔
1136
        item->setBackground(COL_NUM, QColor("#FF8000"));
19✔
1137
    m_secondaryIndex = tmpIndex;
19✔
1138

1139
    emit sideFaderValueChanged();
19✔
1140
}
1141

1142
void VCCueList::slotShowCrossfadePanel(bool enable)
15✔
1143
{
1144
    m_topPercentageLabel->setVisible(enable);
15✔
1145
    m_topStepLabel->setVisible(enable);
15✔
1146
    m_sideFader->setVisible(enable);
15✔
1147
    m_bottomStepLabel->setVisible(enable);
15✔
1148
    m_bottomPercentageLabel->setVisible(enable);
15✔
1149

1150
    emit sideFaderButtonToggled();
15✔
1151
}
15✔
1152

1153
QString VCCueList::topPercentageValue()
×
1154
{
1155
    return m_topPercentageLabel->text();
×
1156
}
1157

1158
QString VCCueList::bottomPercentageValue()
×
1159
{
1160
    return m_bottomPercentageLabel->text();
×
1161
}
1162

1163
QString VCCueList::topStepValue()
×
1164
{
1165
    return m_topStepLabel->text();
×
1166
}
1167

1168
QString VCCueList::bottomStepValue()
×
1169
{
1170
    return m_bottomStepLabel->text();
×
1171
}
1172

1173
int VCCueList::sideFaderValue()
×
1174
{
1175
    return m_sideFader->value();
×
1176
}
1177

1178
bool VCCueList::primaryTop()
×
1179
{
1180
    return m_primaryTop;
×
1181
}
1182

1183
void VCCueList::slotSideFaderButtonChecked(bool enable)
×
1184
{
1185
    m_crossfadeButton->setChecked(enable);
×
1186
}
×
1187

1188
bool VCCueList::isSideFaderVisible()
×
1189
{
1190
    return m_sideFader->isVisible();
×
1191
}
1192

1193
bool VCCueList::sideFaderButtonChecked()
×
1194
{
1195
    return m_crossfadeButton->isChecked();
×
1196
}
1197

1198
void VCCueList::slotSetSideFaderValue(int value)
×
1199
{
1200
    m_sideFader->setValue(value);
×
1201
}
×
1202

1203
void VCCueList::slotSideFaderValueChanged(int value)
×
1204
{
1205
    if (sideFaderMode() == Steps)
×
1206
    {
1207
        value = 255 - value;
×
1208
        m_topPercentageLabel->setText(QString("%1").arg(value));
×
1209

1210
        emit sideFaderValueChanged();
×
1211

1212
        Chaser *ch = chaser();
×
1213
        if (ch == NULL || ch->stopped())
×
1214
            return;
×
1215

1216
        int newStep = value; // by default we assume the Chaser has more than 256 steps
×
1217
        if (ch->stepsCount() < 256)
×
1218
        {
1219
            float stepSize = 255.0 / (float)ch->stepsCount();
×
NEW
1220
            if (value >= 255.0 - stepSize)
×
1221
                newStep = ch->stepsCount() - 1;
×
1222
            else
1223
                newStep = qFloor((float)value / stepSize);
×
1224
        }
1225
        //qDebug() << "value:" << value << "steps:" << ch->stepsCount() << "new step:" << newStep;
1226

1227
        if (newStep == ch->currentStepIndex())
×
1228
            return;
×
1229

1230
        ChaserAction action;
1231
        action.m_action = ChaserSetStepIndex;
×
1232
        action.m_stepIndex = newStep;
×
1233
        action.m_masterIntensity = intensity();
×
1234
        action.m_stepIntensity = getPrimaryIntensity();
×
1235
        action.m_fadeMode = getFadeMode();
×
1236
        ch->setAction(action);
×
1237
    }
1238
    else
1239
    {
1240
        m_topPercentageLabel->setText(QString("%1%").arg(value));
×
1241
        m_bottomPercentageLabel->setText(QString("%1%").arg(100 - value));
×
1242

1243
        emit sideFaderValueChanged();
×
1244

1245
        Chaser *ch = chaser();
×
1246
        if (!(ch == NULL || ch->stopped()))
×
1247
        {
1248
            ch->adjustStepIntensity(qreal(value) / 100.0, m_primaryTop ? m_primaryIndex : m_secondaryIndex,
×
1249
                                    Chaser::FadeControlMode(getFadeMode()));
×
1250
            ch->adjustStepIntensity(qreal(100 - value) / 100.0, m_primaryTop ? m_secondaryIndex : m_primaryIndex,
×
1251
                                    Chaser::FadeControlMode(getFadeMode()));
×
1252
            stopStepIfNeeded(ch);
×
1253
        }
1254
    }
1255

1256
    updateFeedback();
×
1257
}
1258

1259
void VCCueList::stopStepIfNeeded(Chaser *ch)
×
1260
{
1261
    if (ch->runningStepsNumber() != 2)
×
1262
        return;
×
1263

1264
    int primaryValue = m_primaryTop ? m_sideFader->value() : 100 - m_sideFader->value();
×
1265
    int secondaryValue = m_primaryTop ? 100 - m_sideFader->value() : m_sideFader->value();
×
1266

1267
    ChaserAction action;
1268
    action.m_action = ChaserStopStep;
×
1269

1270
    if (primaryValue == 0)
×
1271
    {
1272
        m_primaryTop = !m_primaryTop;
×
1273
        action.m_stepIndex = m_primaryIndex;
×
1274
        ch->setAction(action);
×
1275
    }
1276
    else if (secondaryValue == 0)
×
1277
    {
1278
        action.m_stepIndex = m_secondaryIndex;
×
1279
        ch->setAction(action);
×
1280
    }
1281
}
1282

1283
/*****************************************************************************
1284
 * Key Sequences
1285
 *****************************************************************************/
1286

1287
void VCCueList::setNextKeySequence(const QKeySequence& keySequence)
6✔
1288
{
1289
    m_nextKeySequence = QKeySequence(keySequence);
6✔
1290
}
6✔
1291

1292
QKeySequence VCCueList::nextKeySequence() const
8✔
1293
{
1294
    return m_nextKeySequence;
8✔
1295
}
1296

1297
void VCCueList::setPreviousKeySequence(const QKeySequence& keySequence)
6✔
1298
{
1299
    m_previousKeySequence = QKeySequence(keySequence);
6✔
1300
}
6✔
1301

1302
QKeySequence VCCueList::previousKeySequence() const
8✔
1303
{
1304
    return m_previousKeySequence;
8✔
1305
}
1306

1307
void VCCueList::setPlaybackKeySequence(const QKeySequence& keySequence)
6✔
1308
{
1309
    m_playbackKeySequence = QKeySequence(keySequence);
6✔
1310
}
6✔
1311

1312
QKeySequence VCCueList::playbackKeySequence() const
8✔
1313
{
1314
    return m_playbackKeySequence;
8✔
1315
}
1316

1317
void VCCueList::setStopKeySequence(const QKeySequence &keySequence)
3✔
1318
{
1319
    m_stopKeySequence = QKeySequence(keySequence);
3✔
1320
}
3✔
1321

1322
QKeySequence VCCueList::stopKeySequence() const
3✔
1323
{
1324
    return m_stopKeySequence;
3✔
1325
}
1326

1327
void VCCueList::slotKeyPressed(const QKeySequence& keySequence)
7✔
1328
{
1329
    if (acceptsInput() == false)
7✔
1330
        return;
×
1331

1332
    if (m_nextKeySequence == keySequence)
7✔
1333
        slotNextCue();
3✔
1334
    else if (m_previousKeySequence == keySequence)
4✔
1335
        slotPreviousCue();
2✔
1336
    else if (m_playbackKeySequence == keySequence)
2✔
1337
        slotPlayback();
1✔
1338
    else if (m_stopKeySequence == keySequence)
1✔
1339
        slotStop();
×
1340
}
1341

1342
void VCCueList::updateFeedback()
25✔
1343
{
1344
    int fbv = int(SCALE(float(m_sideFader->value()), 
25✔
1345
                        float(m_sideFader->minimum()),
1346
                        float(m_sideFader->maximum()), 
1347
                        float(0), float(UCHAR_MAX)));
25✔
1348
    sendFeedback(fbv, sideFaderInputSourceId);
25✔
1349

1350
    Chaser *ch = chaser();
25✔
1351
    if (ch == NULL)
25✔
1352
        return;
3✔
1353

1354
    sendFeedback(ch->isRunning() ? UCHAR_MAX : 0, playbackInputSourceId);
22✔
1355
}
1356

1357
/*****************************************************************************
1358
 * External Input
1359
 *****************************************************************************/
1360

1361
void VCCueList::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
12✔
1362
{
1363
    /* Don't let input data through in design mode or if disabled */
1364
    if (acceptsInput() == false)
12✔
1365
        return;
×
1366

1367
    quint32 pagedCh = (page() << 16) | channel;
12✔
1368

1369
    if (checkInputSource(universe, pagedCh, value, sender(), nextInputSourceId))
12✔
1370
    {
1371
        // Use hysteresis for values, in case the cue list is being controlled
1372
        // by a slider. The value has to go to zero before the next non-zero
1373
        // value is accepted as input. And the non-zero values have to visit
1374
        // above $HYSTERESIS before a zero is accepted again.
1375
        if (m_nextLatestValue == 0 && value > 0)
3✔
1376
        {
1377
            slotNextCue();
2✔
1378
            m_nextLatestValue = value;
2✔
1379
        }
1380
        else if (m_nextLatestValue > HYSTERESIS && value == 0)
1✔
1381
        {
1382
            m_nextLatestValue = 0;
1✔
1383
        }
1384

1385
        if (value > HYSTERESIS)
3✔
1386
            m_nextLatestValue = value;
2✔
1387
    }
1388
    else if (checkInputSource(universe, pagedCh, value, sender(), previousInputSourceId))
9✔
1389
    {
1390
        // Use hysteresis for values, in case the cue list is being controlled
1391
        // by a slider. The value has to go to zero before the next non-zero
1392
        // value is accepted as input. And the non-zero values have to visit
1393
        // above $HYSTERESIS before a zero is accepted again.
1394
        if (m_previousLatestValue == 0 && value > 0)
3✔
1395
        {
1396
            slotPreviousCue();
2✔
1397
            m_previousLatestValue = value;
2✔
1398
        }
1399
        else if (m_previousLatestValue > HYSTERESIS && value == 0)
1✔
1400
        {
1401
            m_previousLatestValue = 0;
1✔
1402
        }
1403

1404
        if (value > HYSTERESIS)
3✔
1405
            m_previousLatestValue = value;
2✔
1406
    }
1407
    else if (checkInputSource(universe, pagedCh, value, sender(), playbackInputSourceId))
6✔
1408
    {
1409
        // Use hysteresis for values, in case the cue list is being controlled
1410
        // by a slider. The value has to go to zero before the next non-zero
1411
        // value is accepted as input. And the non-zero values have to visit
1412
        // above $HYSTERESIS before a zero is accepted again.
1413
        if (m_playbackLatestValue == 0 && value > 0)
2✔
1414
        {
1415
            slotPlayback();
1✔
1416
            m_playbackLatestValue = value;
1✔
1417
        }
1418
        else if (m_playbackLatestValue > HYSTERESIS && value == 0)
1✔
1419
        {
1420
            m_playbackLatestValue = 0;
1✔
1421
        }
1422

1423
        if (value > HYSTERESIS)
2✔
1424
            m_playbackLatestValue = value;
1✔
1425
    }
1426
    else if (checkInputSource(universe, pagedCh, value, sender(), stopInputSourceId))
4✔
1427
    {
1428
        // Use hysteresis for values, in case the cue list is being controlled
1429
        // by a slider. The value has to go to zero before the next non-zero
1430
        // value is accepted as input. And the non-zero values have to visit
1431
        // above $HYSTERESIS before a zero is accepted again.
1432
        if (m_stopLatestValue == 0 && value > 0)
×
1433
        {
1434
            slotStop();
×
1435
            m_stopLatestValue = value;
×
1436
        }
1437
        else if (m_stopLatestValue > HYSTERESIS && value == 0)
×
1438
        {
1439
            m_stopLatestValue = 0;
×
1440
        }
1441

1442
        if (value > HYSTERESIS)
×
1443
            m_stopLatestValue = value;
×
1444
    }
1445
    else if (checkInputSource(universe, pagedCh, value, sender(), sideFaderInputSourceId))
4✔
1446
    {
1447
        if (sideFaderMode() == None)
×
1448
            return;
×
1449

1450
        float val = SCALE((float) value, (float) 0, (float) UCHAR_MAX,
×
1451
                          (float) m_sideFader->minimum(),
1452
                          (float) m_sideFader->maximum());
1453
        m_sideFader->setValue(val);
×
1454
    }
1455
}
1456

1457
/*****************************************************************************
1458
 * VCWidget-inherited methods
1459
 *****************************************************************************/
1460

1461
void VCCueList::adjustIntensity(qreal val)
×
1462
{
1463
    Chaser *ch = chaser();
×
1464
    if (ch != NULL)
×
1465
    {
1466
        adjustFunctionIntensity(ch, val);
×
1467
/*
1468
        // Refresh intensity of current steps
1469
        if (!ch->stopped() && sideFaderMode() == Crossfade && m_sideFader->value() != 100)
1470
        {
1471
                ch->adjustStepIntensity((qreal)m_sideFader->value() / 100, m_primaryTop ? m_primaryIndex : m_secondaryIndex);
1472
                ch->adjustStepIntensity((qreal)(100 - m_sideFader->value()) / 100, m_primaryTop ? m_secondaryIndex : m_primaryIndex);
1473
        }
1474
*/
1475
    }
1476

1477
    VCWidget::adjustIntensity(val);
×
1478
}
×
1479

1480
void VCCueList::setCaption(const QString& text)
20✔
1481
{
1482
    VCWidget::setCaption(text);
20✔
1483

1484
    QStringList list;
40✔
1485
    list << "#" << text << tr("Fade In") << tr("Fade Out") << tr("Duration") << tr("Notes");
20✔
1486
    m_tree->setHeaderLabels(list);
20✔
1487
}
20✔
1488

1489
void VCCueList::setFont(const QFont& font)
1✔
1490
{
1491
    VCWidget::setFont(font);
1✔
1492

1493
    QFontMetrics m_fm = QFontMetrics(font);
2✔
1494
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
1495
    int w = m_fm.width("100%");
1496
#else
1497
    int w = m_fm.horizontalAdvance("100%");
1✔
1498
#endif
1499
    m_topPercentageLabel->setFixedWidth(w);
1✔
1500
    m_bottomPercentageLabel->setFixedWidth(w);
1✔
1501
}
1✔
1502

1503
void VCCueList::slotModeChanged(Doc::Mode mode)
23✔
1504
{
1505
    bool enable = false;
23✔
1506
    if (mode == Doc::Operate)
23✔
1507
    {
1508
        m_progress->setStyleSheet(progressFadeStyle);
6✔
1509
        m_progress->setRange(0, m_progress->width());
6✔
1510
        enable = true;
6✔
1511
        // send the initial feedback for the current step slider
1512
        updateFeedback();
6✔
1513
    }
1514
    else
1515
    {
1516
        m_topStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1517
        m_topStepLabel->setText("");
17✔
1518
        m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1519
        m_bottomStepLabel->setText("");
17✔
1520
        m_progress->setStyleSheet(progressDisabledStyle);
17✔
1521
        // reset any previously set background
1522
        QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
17✔
1523
        if (item != NULL)
17✔
1524
            item->setBackground(COL_NUM, m_defCol);
2✔
1525
    }
1526

1527
    enableWidgetUI(enable);
23✔
1528

1529
    /* Always start from the beginning */
1530
    m_tree->setCurrentItem(NULL);
23✔
1531

1532
    VCWidget::slotModeChanged(mode);
23✔
1533

1534
    emit sideFaderValueChanged();
23✔
1535
}
23✔
1536

1537
void VCCueList::editProperties()
×
1538
{
1539
    VCCueListProperties prop(this, m_doc);
×
1540
    if (prop.exec() == QDialog::Accepted)
×
1541
        m_doc->setModified();
×
1542
}
×
1543

1544
void VCCueList::playCueAtIndex(int idx)
4✔
1545
{
1546
    if (mode() != Doc::Operate)
4✔
1547
        return;
×
1548

1549
    m_primaryIndex = idx;
4✔
1550

1551
    Chaser *ch = chaser();
4✔
1552
    if (ch == NULL)
4✔
1553
        return;
×
1554

1555
    if (ch->isRunning())
4✔
1556
    {
1557
        ChaserAction action;
1558
        action.m_action = ChaserSetStepIndex;
3✔
1559
        action.m_stepIndex = m_primaryIndex;
3✔
1560
        action.m_masterIntensity = intensity();
3✔
1561
        action.m_stepIntensity = getPrimaryIntensity();
3✔
1562
        action.m_fadeMode = getFadeMode();
3✔
1563
        ch->setAction(action);
3✔
1564
    }
1565
    else
1566
    {
1567
        startChaser(m_primaryIndex);
1✔
1568
    }
1569

1570
    if (sideFaderMode() == Crossfade)
4✔
1571
        setFaderInfo(m_primaryIndex);
×
1572
}
1573

1574
FunctionParent VCCueList::functionParent() const
4✔
1575
{
1576
    return FunctionParent(FunctionParent::ManualVCWidget, id());
4✔
1577
}
1578

1579
/*****************************************************************************
1580
 * Load & Save
1581
 *****************************************************************************/
1582

1583
bool VCCueList::loadXML(QXmlStreamReader &root)
3✔
1584
{
1585
    QList <quint32> legacyStepList;
6✔
1586

1587
    if (root.name() != KXMLQLCVCCueList)
3✔
1588
    {
1589
        qWarning() << Q_FUNC_INFO << "CueList node not found";
1✔
1590
        return false;
1✔
1591
    }
1592

1593
    /* Widget commons */
1594
    loadXMLCommon(root);
2✔
1595

1596
    /* Children */
1597
    while (root.readNextStartElement())
18✔
1598
    {
1599
        if (root.name() == KXMLQLCWindowState)
16✔
1600
        {
1601
            bool visible = false;
1✔
1602
            int x = 0, y = 0, w = 0, h = 0;
1✔
1603
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
1✔
1604
            setGeometry(x, y, w, h);
1✔
1605
        }
1606
        else if (root.name() == KXMLQLCVCWidgetAppearance)
15✔
1607
        {
1608
            loadXMLAppearance(root);
1✔
1609
        }
1610
        else if (root.name() == KXMLQLCVCCueListNext)
14✔
1611
        {
1612
            QString str = loadXMLSources(root, nextInputSourceId);
2✔
1613
            if (str.isEmpty() == false)
1✔
1614
                m_nextKeySequence = stripKeySequence(QKeySequence(str));
1✔
1615
        }
1616
        else if (root.name() == KXMLQLCVCCueListPrevious)
13✔
1617
        {
1618
            QString str = loadXMLSources(root, previousInputSourceId);
2✔
1619
            if (str.isEmpty() == false)
1✔
1620
                m_previousKeySequence = stripKeySequence(QKeySequence(str));
1✔
1621
        }
1622
        else if (root.name() == KXMLQLCVCCueListPlayback)
12✔
1623
        {
1624
            QString str = loadXMLSources(root, playbackInputSourceId);
2✔
1625
            if (str.isEmpty() == false)
1✔
1626
                m_playbackKeySequence = stripKeySequence(QKeySequence(str));
1✔
1627
        }
1628
        else if (root.name() == KXMLQLCVCCueListStop)
11✔
1629
        {
1630
            QString str = loadXMLSources(root, stopInputSourceId);
2✔
1631
            if (str.isEmpty() == false)
1✔
1632
                m_stopKeySequence = stripKeySequence(QKeySequence(str));
1✔
1633
        }
1634
        else if (root.name() == KXMLQLCVCCueListSlidersMode)
10✔
1635
        {
1636
            setSideFaderMode(stringToFaderMode(root.readElementText()));
×
1637
        }
1638
        else if (root.name() == KXMLQLCVCCueListCrossfadeLeft)
10✔
1639
        {
1640
            loadXMLSources(root, sideFaderInputSourceId);
×
1641
        }
1642
        else if (root.name() == KXMLQLCVCCueListCrossfadeRight) /* Legacy */
10✔
1643
        {
1644
            root.skipCurrentElement();
×
1645
        }
1646
        else if (root.name() == KXMLQLCVCWidgetKey) /* Legacy */
10✔
1647
        {
1648
            setNextKeySequence(QKeySequence(root.readElementText()));
×
1649
        }
1650
        else if (root.name() == KXMLQLCVCCueListChaser)
10✔
1651
        {
1652
            setChaser(root.readElementText().toUInt());
×
1653
        }
1654
        else if (root.name() == KXMLQLCVCCueListPlaybackLayout)
10✔
1655
        {
1656
            PlaybackLayout layout = PlaybackLayout(root.readElementText().toInt());
×
1657
            if (layout != PlayPauseStop && layout != PlayStopPause)
×
1658
            {
1659
                qWarning() << Q_FUNC_INFO << "Playback layout" << layout << "does not exist.";
×
1660
                layout = PlayPauseStop;
×
1661
            }
1662
            setPlaybackLayout(layout);
×
1663
        }
1664
        else if (root.name() == KXMLQLCVCCueListNextPrevBehavior)
10✔
1665
        {
1666
            NextPrevBehavior nextPrev = NextPrevBehavior(root.readElementText().toInt());
×
1667
            if (nextPrev != DefaultRunFirst
×
1668
                    && nextPrev != RunNext
×
1669
                    && nextPrev != Select
×
1670
                    && nextPrev != Nothing)
×
1671
            {
1672
                qWarning() << Q_FUNC_INFO << "Next/Prev behavior" << nextPrev << "does not exist.";
×
1673
                nextPrev = DefaultRunFirst;
×
1674
            }
1675
            setNextPrevBehavior(nextPrev);
×
1676
        }
1677
        else if (root.name() == KXMLQLCVCCueListCrossfade)
10✔
1678
        {
1679
            m_crossfadeButton->setChecked(true);
×
1680
            root.skipCurrentElement();
×
1681
        }
1682
        else if (root.name() == KXMLQLCVCCueListFunction)
10✔
1683
        {
1684
            // Collect legacy file format steps into a list
1685
            legacyStepList << root.readElementText().toUInt();
6✔
1686
        }
1687
        else
1688
        {
1689
            qWarning() << Q_FUNC_INFO << "Unknown cuelist tag:" << root.name().toString();
4✔
1690
            root.skipCurrentElement();
4✔
1691
        }
1692
    }
1693

1694
    if (legacyStepList.isEmpty() == false)
2✔
1695
    {
1696
        /* Construct a new chaser from legacy step functions and use that chaser */
1697
        Chaser *chaser = new Chaser(m_doc);
1✔
1698
        chaser->setName(caption());
1✔
1699

1700
        // Legacy cue lists relied on individual functions' timings and a common hold time
1701
        chaser->setFadeInMode(Chaser::Default);
1✔
1702
        chaser->setFadeOutMode(Chaser::Default);
1✔
1703
        chaser->setDurationMode(Chaser::Common);
1✔
1704

1705
        foreach (quint32 id, legacyStepList)
13✔
1706
        {
1707
            Function *function = m_doc->function(id);
6✔
1708
            if (function == NULL)
6✔
1709
                continue;
2✔
1710

1711
            // Legacy cuelists relied on individual functions' fadein/out speed and
1712
            // infinite duration. So don't touch them at all.
1713
            ChaserStep step(id);
8✔
1714
            chaser->addStep(step);
4✔
1715
        }
1716

1717
        // Add the chaser to Doc and attach it to the cue list
1718
        m_doc->addFunction(chaser);
1✔
1719
        setChaser(chaser->id());
1✔
1720
    }
1721

1722
    return true;
2✔
1723
}
1724

1725
bool VCCueList::saveXML(QXmlStreamWriter *doc)
1✔
1726
{
1727
    Q_ASSERT(doc != NULL);
1✔
1728

1729
    /* VC CueList entry */
1730
    doc->writeStartElement(KXMLQLCVCCueList);
1✔
1731

1732
    saveXMLCommon(doc);
1✔
1733

1734
    /* Window state */
1735
    saveXMLWindowState(doc);
1✔
1736

1737
    /* Appearance */
1738
    saveXMLAppearance(doc);
1✔
1739

1740
    /* Chaser */
1741
    doc->writeTextElement(KXMLQLCVCCueListChaser, QString::number(chaserID()));
1✔
1742

1743
    /* Playback layout */
1744
    if (playbackLayout() != PlayPauseStop)
1✔
1745
        doc->writeTextElement(KXMLQLCVCCueListPlaybackLayout, QString::number(playbackLayout()));
×
1746

1747
    /* Next/Prev behavior */
1748
    doc->writeTextElement(KXMLQLCVCCueListNextPrevBehavior, QString::number(nextPrevBehavior()));
1✔
1749

1750
    /* Next cue */
1751
    doc->writeStartElement(KXMLQLCVCCueListNext);
1✔
1752
    if (m_nextKeySequence.toString().isEmpty() == false)
1✔
1753
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_nextKeySequence.toString());
1✔
1754
    saveXMLInput(doc, inputSource(nextInputSourceId));
1✔
1755
    doc->writeEndElement();
1✔
1756

1757
    /* Previous cue */
1758
    doc->writeStartElement(KXMLQLCVCCueListPrevious);
1✔
1759
    if (m_previousKeySequence.toString().isEmpty() == false)
1✔
1760
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_previousKeySequence.toString());
1✔
1761
    saveXMLInput(doc, inputSource(previousInputSourceId));
1✔
1762
    doc->writeEndElement();
1✔
1763

1764
    /* Cue list playback */
1765
    doc->writeStartElement(KXMLQLCVCCueListPlayback);
1✔
1766
    if (m_playbackKeySequence.toString().isEmpty() == false)
1✔
1767
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_playbackKeySequence.toString());
1✔
1768
    saveXMLInput(doc, inputSource(playbackInputSourceId));
1✔
1769
    doc->writeEndElement();
1✔
1770

1771
    /* Cue list stop */
1772
    doc->writeStartElement(KXMLQLCVCCueListStop);
1✔
1773
    if (m_stopKeySequence.toString().isEmpty() == false)
1✔
1774
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_stopKeySequence.toString());
1✔
1775
    saveXMLInput(doc, inputSource(stopInputSourceId));
1✔
1776
    doc->writeEndElement();
1✔
1777

1778
    /* Crossfade cue list */
1779
    if (sideFaderMode() != None)
1✔
1780
        doc->writeTextElement(KXMLQLCVCCueListSlidersMode, faderModeToString(sideFaderMode()));
1✔
1781

1782
    QSharedPointer<QLCInputSource> cf1Src = inputSource(sideFaderInputSourceId);
1✔
1783
    if (!cf1Src.isNull() && cf1Src->isValid())
1✔
1784
    {
1785
        doc->writeStartElement(KXMLQLCVCCueListCrossfadeLeft);
×
1786
        saveXMLInput(doc, cf1Src);
×
1787
        doc->writeEndElement();
×
1788
    }
1789

1790
    /* End the <CueList> tag */
1791
    doc->writeEndElement();
1✔
1792

1793
    return true;
2✔
1794
}
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