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

mcallegari / qlcplus / 19409821768

16 Nov 2025 06:06PM UTC coverage: 34.233% (-0.01%) from 34.243%
19409821768

push

github

mcallegari
vc/soloframe: add an option to exclude functions monitored by buttons to be stopped

3 of 38 new or added lines in 9 files covered. (7.89%)

2 existing lines in 2 files now uncovered.

17724 of 51774 relevant lines covered (34.23%)

19630.45 hits per line

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

61.18
/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)
15✔
90
    , m_playbackLayout(PlayPauseStop)
15✔
91
    , m_timer(NULL)
15✔
92
    , m_primaryIndex(0)
15✔
93
    , m_secondaryIndex(0)
15✔
94
    , m_primaryTop(true)
15✔
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());
15✔
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;
15✔
251
    QVariant var = settings.value(SETTINGS_CUELIST_SIZE);
15✔
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()
89✔
386
{
387
    if (m_chaserID == Function::invalidId())
89✔
388
        return NULL;
6✔
389
    Chaser *chaser = qobject_cast<Chaser*>(m_doc->function(m_chaserID));
83✔
390
    return chaser;
83✔
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());
12✔
404
    while (it.hasNext() == true)
59✔
405
    {
406
        ChaserStep step(it.next());
47✔
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
    }
47✔
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
}
12✔
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

NEW
559
void VCCueList::notifyFunctionStarting(quint32 fid, qreal intensity, bool excludeMonitored)
×
560
{
561
    Q_UNUSED(intensity)
562
    Q_UNUSED(excludeMonitored)
563

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

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

570
    stopChaser();
×
571
}
572

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

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

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

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

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

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

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

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

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

661
    emit playbackButtonClicked();
2✔
662
}
663

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

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

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

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

706
    emit stopButtonClicked();
×
707
}
708

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

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

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

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

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

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

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

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

819
        float stepVal;
820
        int stepsCount = m_tree->topLevelItemCount();
×
821
        if (stepsCount < 256) 
×
822
        {
823
            stepVal = 256.0 / (float)stepsCount; //divide up the full 0..255 range
×
824
            stepVal = qFloor((stepVal * 100000.0) + 0.5) / 100000.0; //round to 5 decimals to fix corner cases
×
825
        }
826
        else 
827
        {
828
            stepVal = 1.0;
×
829
        }
830
        
831
        // value->step# truncates down in slotSideFaderValueChanged; so use ceiling for step#->value
832
        float slValue = stepVal * (float)stepNumber;
×
833
        if (slValue > 255)
×
834
            slValue = 255.0;
×
835

836
        int upperBound = 255 - qCeil(slValue);
×
837
        int lowerBound = qFloor(256.0 - slValue - stepVal);
×
838
        // if the Step slider is already in range, then do not set its value
839
        // this means a user interaction is going on, either with the mouse or external controller
840
        if (m_sideFader->value() < lowerBound || m_sideFader->value() >= upperBound)
×
841
        {
842
            m_sideFader->blockSignals(true);
×
843
            m_sideFader->setValue(upperBound);
×
844
            m_topPercentageLabel->setText(QString("%1").arg(qCeil(slValue)));
×
845
            m_sideFader->blockSignals(false);
×
846

847
            //qDebug() << "Slider value:" << m_sideFader->value() << "->" << 255-qCeil(slValue) 
848
            //    << "(disp:" << slValue << ")" << "Step range:" << upperBound << lowerBound 
849
            //    << "(stepSize:" << stepVal << ")" 
850
            //    << "(raw lower:" << (256.0 - slValue - stepVal) << ")";
851
        }
852
    }
853
    else
854
    {
855
        setFaderInfo(m_primaryIndex);
19✔
856
    }
857
    emit stepChanged(m_primaryIndex);
19✔
858
    emit sideFaderValueChanged();
19✔
859
}
860

861
void VCCueList::slotItemActivated(QTreeWidgetItem *item)
5✔
862
{
863
    if (mode() != Doc::Operate)
5✔
864
        return;
1✔
865

866
    playCueAtIndex(m_tree->indexOfTopLevelItem(item));
4✔
867
}
868

869
void VCCueList::slotItemChanged(QTreeWidgetItem *item, int column)
374✔
870
{
871
    if (m_listIsUpdating || column != COL_NOTES)
374✔
872
        return;
374✔
873

874
    Chaser *ch = chaser();
×
875
    if (ch == NULL)
×
876
        return;
×
877

878
    QString itemText = item->text(column);
×
879
    int idx = m_tree->indexOfTopLevelItem(item);
×
880
    ChaserStep step = ch->steps().at(idx);
×
881

882
    step.note = itemText;
×
883
    ch->replaceStep(step, idx);
×
884

885
    emit stepNoteChanged(idx, itemText);
×
886
}
×
887

888
void VCCueList::slotStepNoteChanged(int idx, QString note)
×
889
{
890
    Chaser *ch = chaser();
×
891
    if (ch == NULL)
×
892
        return;
×
893
    ChaserStep step = ch->steps().at(idx);
×
894
    step.note = note;
×
895
    ch->replaceStep(step, idx);
×
896
}
×
897

898
void VCCueList::slotFunctionRunning(quint32 fid)
4✔
899
{
900
    if (fid != m_chaserID)
4✔
901
        return;
×
902

903
    if (playbackLayout() == PlayPauseStop)
4✔
904
        m_playbackButton->setIcon(QIcon(":/player_pause.png"));
4✔
905
    else if (playbackLayout() == PlayStopPause)
×
906
        m_playbackButton->setIcon(QIcon(":/player_stop.png"));
×
907
    m_timer->start(PROGRESS_INTERVAL);
4✔
908
    emit playbackStatusChanged();
4✔
909
    updateFeedback();
4✔
910
}
911

912
void VCCueList::slotFunctionStopped(quint32 fid)
14✔
913
{
914
    if (fid != m_chaserID)
14✔
915
        return;
×
916

917
    m_playbackButton->setIcon(QIcon(":/player_play.png"));
14✔
918
    m_topStepLabel->setText("");
14✔
919
    m_topStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
920
    m_bottomStepLabel->setText("");
14✔
921
    m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
922
    // reset any previously set background
923
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
14✔
924
    if (item != NULL)
14✔
925
        item->setBackground(COL_NUM, m_defCol);
11✔
926

927
    emit stepChanged(-1);
14✔
928

929
    m_progress->setFormat("");
14✔
930
    m_progress->setValue(0);    
14✔
931

932
    emit progressStateChanged();
14✔
933
    emit sideFaderValueChanged();
14✔
934
    emit playbackStatusChanged();
14✔
935

936
    qDebug() << Q_FUNC_INFO << "Cue stopped";
14✔
937
    updateFeedback();
14✔
938
}
939

940
void VCCueList::slotProgressTimeout()
×
941
{
942
    Chaser *ch = chaser();
×
943
    if (ch == NULL || !ch->isRunning())
×
944
        return;
×
945

946
    ChaserRunnerStep step(ch->currentRunningStep());
×
947
    if (step.m_function != NULL)
×
948
    {
949
        int status = m_progress->property("status").toInt();
×
950
        int newstatus;
951
        if (step.m_fadeIn == Function::defaultSpeed())
×
952
            newstatus = 1;
×
953
        else if (step.m_elapsed > (quint32)step.m_fadeIn)
×
954
            newstatus = 1;
×
955
        else
956
            newstatus = 0;
×
957

958
        if (newstatus != status)
×
959
        {
960
            if (newstatus == 0)
×
961
                m_progress->setStyleSheet(progressFadeStyle);
×
962
            else
963
                m_progress->setStyleSheet(progressHoldStyle);
×
964
            m_progress->setProperty("status", newstatus);
×
965
        }
966
        if (step.m_duration == Function::infiniteSpeed())
×
967
        {
968
            if (newstatus == 0 && step.m_fadeIn != Function::defaultSpeed())
×
969
            {
970
                double progress = ((double)step.m_elapsed / (double)step.m_fadeIn) * (double)m_progress->width();
×
971
                m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_fadeIn - step.m_elapsed)));
×
972
                m_progress->setValue(progress);
×
973

974
                emit progressStateChanged();
×
975
            }
976
            else
977
            {
978
                m_progress->setValue(m_progress->maximum());
×
979
                m_progress->setFormat("");
×
980

981
                emit progressStateChanged();
×
982
            }
983
            return;
×
984
        }
985
        else
986
        {
987
            double progress = ((double)step.m_elapsed / (double)step.m_duration) * (double)m_progress->width();
×
988
            m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_duration - step.m_elapsed)));
×
989
            m_progress->setValue(progress);
×
990

991
            emit progressStateChanged();
×
992
        }
993
    }
994
    else
995
    {
996
        m_progress->setValue(0);
×
997
    }
998
}
999

1000
QString VCCueList::progressText()
×
1001
{
1002
    return m_progress->text();
×
1003
}
1004

1005
double VCCueList::progressPercent()
×
1006
{
1007
    return ((double)m_progress->value() * 100) / (double)m_progress->width();
×
1008
}
1009

1010
void VCCueList::startChaser(int startIndex)
4✔
1011
{
1012
    Chaser *ch = chaser();
4✔
1013
    if (ch == NULL)
4✔
1014
        return;
×
1015

1016
    adjustFunctionIntensity(ch, intensity());
4✔
1017

1018
    ChaserAction action;
1019
    action.m_action = ChaserSetStepIndex;
4✔
1020
    action.m_stepIndex = startIndex;
4✔
1021
    action.m_masterIntensity = intensity();
4✔
1022
    action.m_stepIntensity = getPrimaryIntensity();
4✔
1023
    action.m_fadeMode = getFadeMode();
4✔
1024
    ch->setAction(action);
4✔
1025

1026
    ch->start(m_doc->masterTimer(), functionParent());
4✔
1027
    emit functionStarting(m_chaserID);
4✔
1028
}
1029

1030
void VCCueList::stopChaser()
×
1031
{
1032
    Chaser *ch = chaser();
×
1033
    if (ch == NULL)
×
1034
        return;
×
1035

1036
    ch->stop(functionParent());
×
1037
    resetIntensityOverrideAttribute();
×
1038
}
1039

1040
int VCCueList::getFadeMode()
20✔
1041
{
1042
    if (sideFaderMode() != Crossfade)
20✔
1043
        return Chaser::FromFunction;
20✔
1044

1045
    if (m_sideFader->value() != 0 && m_sideFader->value() != 100)
×
1046
        return Chaser::BlendedCrossfade;
×
1047

1048
    return Chaser::Blended;
×
1049
}
1050

1051
void VCCueList::setNextPrevBehavior(NextPrevBehavior nextPrev)
×
1052
{
1053
    Q_ASSERT(nextPrev == DefaultRunFirst
×
1054
            || nextPrev == RunNext
1055
            || nextPrev == Select
1056
            || nextPrev == Nothing);
1057
    m_nextPrevBehavior = nextPrev;
×
1058
}
×
1059

1060
VCCueList::NextPrevBehavior VCCueList::nextPrevBehavior() const
1✔
1061
{
1062
    return m_nextPrevBehavior;
1✔
1063
}
1064

1065
void VCCueList::setPlaybackLayout(VCCueList::PlaybackLayout layout)
×
1066
{
1067
    if (layout == m_playbackLayout)
×
1068
        return;
×
1069

1070
    if (layout == PlayStopPause)
×
1071
    {
1072
        m_stopButton->setIcon(QIcon(":/player_pause.png"));
×
1073
        m_playbackButton->setToolTip(tr("Play/Stop Cue list"));
×
1074
        m_stopButton->setToolTip(tr("Pause Cue list"));
×
1075
    }
1076
    else if (layout == PlayPauseStop)
×
1077
    {
1078
        m_stopButton->setIcon(QIcon(":/player_stop.png"));
×
1079
        m_playbackButton->setToolTip(tr("Play/Pause Cue list"));
×
1080
        m_stopButton->setToolTip(tr("Stop Cue list"));
×
1081
    }
1082
    else
1083
    {
1084
        qWarning() << "Playback layout" << layout << "doesn't exist!";
×
1085
        layout = PlayPauseStop;
×
1086
    }
1087

1088
    m_playbackLayout = layout;
×
1089
}
1090

1091
VCCueList::PlaybackLayout VCCueList::playbackLayout() const
7✔
1092
{
1093
    return m_playbackLayout;
7✔
1094
}
1095

1096
VCCueList::FaderMode VCCueList::sideFaderMode() const
67✔
1097
{
1098
    return m_slidersMode;
67✔
1099
}
1100

1101
void VCCueList::setSideFaderMode(VCCueList::FaderMode mode)
3✔
1102
{
1103
    m_slidersMode = mode;
3✔
1104

1105
    bool show = (mode == None) ? false : true;
3✔
1106
    m_crossfadeButton->setVisible(show);
3✔
1107
    m_topPercentageLabel->setVisible(show);
3✔
1108
    m_topStepLabel->setVisible(mode == Steps ? false : show);
3✔
1109
    m_sideFader->setVisible(show);
3✔
1110
    m_bottomPercentageLabel->setVisible(mode == Steps ? false : show);
3✔
1111
    m_bottomStepLabel->setVisible(show);
3✔
1112
    m_sideFader->setMaximum(mode == Steps ? 255 : 100);
3✔
1113
    m_sideFader->setValue(mode == Steps ? 255 : 100);
3✔
1114
}
3✔
1115

1116
VCCueList::FaderMode VCCueList::stringToFaderMode(QString modeStr)
×
1117
{
1118
    if (modeStr == "Crossfade")
×
1119
        return Crossfade;
×
1120
    else if (modeStr == "Steps")
×
1121
        return Steps;
×
1122

1123
    return None;
×
1124
}
1125

1126
QString VCCueList::faderModeToString(VCCueList::FaderMode mode)
1✔
1127
{
1128
    if (mode == Crossfade)
1✔
1129
        return "Crossfade";
1✔
1130
    else if (mode == Steps)
×
1131
        return "Steps";
×
1132

1133
    return "None";
×
1134
}
1135

1136
/*****************************************************************************
1137
 * Crossfade
1138
 *****************************************************************************/
1139
void VCCueList::setFaderInfo(int index)
19✔
1140
{
1141
    Chaser *ch = chaser();
19✔
1142
    if (ch == NULL || !ch->isRunning())
19✔
1143
        return;
×
1144

1145
    int tmpIndex = ch->computeNextStep(index);
19✔
1146

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

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

1153
    // reset any previously set background
1154
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
19✔
1155
    if (item != NULL)
19✔
1156
        item->setBackground(COL_NUM, m_defCol);
19✔
1157

1158
    item = m_tree->topLevelItem(tmpIndex);
19✔
1159
    if (item != NULL)
19✔
1160
        item->setBackground(COL_NUM, QColor("#FF8000"));
19✔
1161
    m_secondaryIndex = tmpIndex;
19✔
1162

1163
    emit sideFaderValueChanged();
19✔
1164
}
1165

1166
void VCCueList::slotShowCrossfadePanel(bool enable)
15✔
1167
{
1168
    m_topPercentageLabel->setVisible(enable);
15✔
1169
    m_topStepLabel->setVisible(enable);
15✔
1170
    m_sideFader->setVisible(enable);
15✔
1171
    m_bottomStepLabel->setVisible(enable);
15✔
1172
    m_bottomPercentageLabel->setVisible(enable);
15✔
1173

1174
    emit sideFaderButtonToggled();
15✔
1175
}
15✔
1176

1177
QString VCCueList::topPercentageValue()
×
1178
{
1179
    return m_topPercentageLabel->text();
×
1180
}
1181

1182
QString VCCueList::bottomPercentageValue()
×
1183
{
1184
    return m_bottomPercentageLabel->text();
×
1185
}
1186

1187
QString VCCueList::topStepValue()
×
1188
{
1189
    return m_topStepLabel->text();
×
1190
}
1191

1192
QString VCCueList::bottomStepValue()
×
1193
{
1194
    return m_bottomStepLabel->text();
×
1195
}
1196

1197
int VCCueList::sideFaderValue()
×
1198
{
1199
    return m_sideFader->value();
×
1200
}
1201

1202
bool VCCueList::primaryTop()
×
1203
{
1204
    return m_primaryTop;
×
1205
}
1206

1207
void VCCueList::slotSideFaderButtonChecked(bool enable)
×
1208
{
1209
    m_crossfadeButton->setChecked(enable);
×
1210
    emit sideFaderButtonChecked();
×
1211
}
×
1212

1213
bool VCCueList::isSideFaderVisible()
×
1214
{
1215
    return m_sideFader->isVisible();
×
1216
}
1217

1218
bool VCCueList::sideFaderButtonIsChecked()
×
1219
{
1220
    return m_crossfadeButton->isChecked();
×
1221
}
1222

1223
void VCCueList::slotSetSideFaderValue(int value)
×
1224
{
1225
    m_sideFader->setValue(value);
×
1226
}
×
1227

1228
void VCCueList::slotSideFaderValueChanged(int value)
×
1229
{
1230
    if (sideFaderMode() == Steps)
×
1231
    {
1232
        value = 255 - value;
×
1233
        m_topPercentageLabel->setText(QString("%1").arg(value));
×
1234

1235
        emit sideFaderValueChanged();
×
1236

1237
        Chaser *ch = chaser();
×
1238
        if (ch == NULL || ch->stopped())
×
1239
            return;
×
1240

1241
        int newStep = value; // by default we assume the Chaser has more than 256 steps
×
1242
        if (ch->stepsCount() < 256)
×
1243
        {
1244
            float stepSize = 256.0 / (float)ch->stepsCount();  //divide up the full 0..255 range
×
1245
            stepSize = qFloor((stepSize * 100000.0) + 0.5) / 100000.0; //round to 5 decimals to fix corner cases
×
1246
            if (value >= 256.0 - stepSize)
×
1247
                newStep = ch->stepsCount() - 1;
×
1248
            else
1249
                newStep = qFloor((float)value / stepSize);
×
1250
            //qDebug() << "value:" << value << " new step:" << newStep << " stepSize:" << stepSize;
1251
        }
1252

1253
        if (newStep == ch->currentStepIndex())
×
1254
            return;
×
1255

1256
        ChaserAction action;
1257
        action.m_action = ChaserSetStepIndex;
×
1258
        action.m_stepIndex = newStep;
×
1259
        action.m_masterIntensity = intensity();
×
1260
        action.m_stepIntensity = getPrimaryIntensity();
×
1261
        action.m_fadeMode = getFadeMode();
×
1262
        ch->setAction(action);
×
1263
    }
1264
    else
1265
    {
1266
        m_topPercentageLabel->setText(QString("%1%").arg(value));
×
1267
        m_bottomPercentageLabel->setText(QString("%1%").arg(100 - value));
×
1268

1269
        emit sideFaderValueChanged();
×
1270

1271
        Chaser *ch = chaser();
×
1272
        if (!(ch == NULL || ch->stopped()))
×
1273
        {
1274
            ch->adjustStepIntensity(qreal(value) / 100.0, m_primaryTop ? m_primaryIndex : m_secondaryIndex,
×
1275
                                    Chaser::FadeControlMode(getFadeMode()));
×
1276
            ch->adjustStepIntensity(qreal(100 - value) / 100.0, m_primaryTop ? m_secondaryIndex : m_primaryIndex,
×
1277
                                    Chaser::FadeControlMode(getFadeMode()));
×
1278
            stopStepIfNeeded(ch);
×
1279
        }
1280
    }
1281

1282
    updateFeedback();
×
1283
}
1284

1285
void VCCueList::stopStepIfNeeded(Chaser *ch)
×
1286
{
1287
    if (ch->runningStepsNumber() != 2)
×
1288
        return;
×
1289

1290
    int primaryValue = m_primaryTop ? m_sideFader->value() : 100 - m_sideFader->value();
×
1291
    int secondaryValue = m_primaryTop ? 100 - m_sideFader->value() : m_sideFader->value();
×
1292

1293
    ChaserAction action;
1294
    action.m_action = ChaserStopStep;
×
1295

1296
    if (primaryValue == 0)
×
1297
    {
1298
        m_primaryTop = !m_primaryTop;
×
1299
        action.m_stepIndex = m_primaryIndex;
×
1300
        ch->setAction(action);
×
1301
    }
1302
    else if (secondaryValue == 0)
×
1303
    {
1304
        action.m_stepIndex = m_secondaryIndex;
×
1305
        ch->setAction(action);
×
1306
    }
1307
}
1308

1309
/*****************************************************************************
1310
 * Key Sequences
1311
 *****************************************************************************/
1312

1313
void VCCueList::setNextKeySequence(const QKeySequence& keySequence)
6✔
1314
{
1315
    m_nextKeySequence = QKeySequence(keySequence);
6✔
1316
}
6✔
1317

1318
QKeySequence VCCueList::nextKeySequence() const
8✔
1319
{
1320
    return m_nextKeySequence;
8✔
1321
}
1322

1323
void VCCueList::setPreviousKeySequence(const QKeySequence& keySequence)
6✔
1324
{
1325
    m_previousKeySequence = QKeySequence(keySequence);
6✔
1326
}
6✔
1327

1328
QKeySequence VCCueList::previousKeySequence() const
8✔
1329
{
1330
    return m_previousKeySequence;
8✔
1331
}
1332

1333
void VCCueList::setPlaybackKeySequence(const QKeySequence& keySequence)
6✔
1334
{
1335
    m_playbackKeySequence = QKeySequence(keySequence);
6✔
1336
}
6✔
1337

1338
QKeySequence VCCueList::playbackKeySequence() const
8✔
1339
{
1340
    return m_playbackKeySequence;
8✔
1341
}
1342

1343
void VCCueList::setStopKeySequence(const QKeySequence &keySequence)
3✔
1344
{
1345
    m_stopKeySequence = QKeySequence(keySequence);
3✔
1346
}
3✔
1347

1348
QKeySequence VCCueList::stopKeySequence() const
3✔
1349
{
1350
    return m_stopKeySequence;
3✔
1351
}
1352

1353
void VCCueList::slotKeyPressed(const QKeySequence& keySequence)
7✔
1354
{
1355
    if (acceptsInput() == false)
7✔
1356
        return;
×
1357

1358
    if (m_nextKeySequence == keySequence)
7✔
1359
        slotNextCue();
3✔
1360
    else if (m_previousKeySequence == keySequence)
4✔
1361
        slotPreviousCue();
2✔
1362
    else if (m_playbackKeySequence == keySequence)
2✔
1363
        slotPlayback();
1✔
1364
    else if (m_stopKeySequence == keySequence)
1✔
1365
        slotStop();
×
1366
}
1367

1368
void VCCueList::updateFeedback()
26✔
1369
{
1370
    int fbv = int(SCALE(float(m_sideFader->value()), 
26✔
1371
                        float(m_sideFader->minimum()),
1372
                        float(m_sideFader->maximum()), 
1373
                        float(0), float(UCHAR_MAX)));
26✔
1374
    sendFeedback(fbv, sideFaderInputSourceId);
26✔
1375

1376
    Chaser *ch = chaser();
26✔
1377
    if (ch == NULL)
26✔
1378
        return;
3✔
1379

1380
    sendFeedback(ch->isRunning() ? UCHAR_MAX : 0, playbackInputSourceId);
23✔
1381
}
1382

1383
/*****************************************************************************
1384
 * External Input
1385
 *****************************************************************************/
1386

1387
void VCCueList::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
12✔
1388
{
1389
    /* Don't let input data through in design mode or if disabled */
1390
    if (acceptsInput() == false)
12✔
1391
        return;
×
1392

1393
    quint32 pagedCh = (page() << 16) | channel;
12✔
1394

1395
    if (checkInputSource(universe, pagedCh, value, sender(), nextInputSourceId))
12✔
1396
    {
1397
        // Use hysteresis for values, in case the cue list is being controlled
1398
        // by a slider. The value has to go to zero before the next non-zero
1399
        // value is accepted as input. And the non-zero values have to visit
1400
        // above $HYSTERESIS before a zero is accepted again.
1401
        if (m_nextLatestValue == 0 && value > 0)
3✔
1402
        {
1403
            slotNextCue();
2✔
1404
            m_nextLatestValue = value;
2✔
1405
        }
1406
        else if (m_nextLatestValue > HYSTERESIS && value == 0)
1✔
1407
        {
1408
            m_nextLatestValue = 0;
1✔
1409
        }
1410

1411
        if (value > HYSTERESIS)
3✔
1412
            m_nextLatestValue = value;
2✔
1413
    }
1414
    else if (checkInputSource(universe, pagedCh, value, sender(), previousInputSourceId))
9✔
1415
    {
1416
        // Use hysteresis for values, in case the cue list is being controlled
1417
        // by a slider. The value has to go to zero before the next non-zero
1418
        // value is accepted as input. And the non-zero values have to visit
1419
        // above $HYSTERESIS before a zero is accepted again.
1420
        if (m_previousLatestValue == 0 && value > 0)
3✔
1421
        {
1422
            slotPreviousCue();
2✔
1423
            m_previousLatestValue = value;
2✔
1424
        }
1425
        else if (m_previousLatestValue > HYSTERESIS && value == 0)
1✔
1426
        {
1427
            m_previousLatestValue = 0;
1✔
1428
        }
1429

1430
        if (value > HYSTERESIS)
3✔
1431
            m_previousLatestValue = value;
2✔
1432
    }
1433
    else if (checkInputSource(universe, pagedCh, value, sender(), playbackInputSourceId))
6✔
1434
    {
1435
        // Use hysteresis for values, in case the cue list is being controlled
1436
        // by a slider. The value has to go to zero before the next non-zero
1437
        // value is accepted as input. And the non-zero values have to visit
1438
        // above $HYSTERESIS before a zero is accepted again.
1439
        if (m_playbackLatestValue == 0 && value > 0)
2✔
1440
        {
1441
            slotPlayback();
1✔
1442
            m_playbackLatestValue = value;
1✔
1443
        }
1444
        else if (m_playbackLatestValue > HYSTERESIS && value == 0)
1✔
1445
        {
1446
            m_playbackLatestValue = 0;
1✔
1447
        }
1448

1449
        if (value > HYSTERESIS)
2✔
1450
            m_playbackLatestValue = value;
1✔
1451
    }
1452
    else if (checkInputSource(universe, pagedCh, value, sender(), stopInputSourceId))
4✔
1453
    {
1454
        // Use hysteresis for values, in case the cue list is being controlled
1455
        // by a slider. The value has to go to zero before the next non-zero
1456
        // value is accepted as input. And the non-zero values have to visit
1457
        // above $HYSTERESIS before a zero is accepted again.
1458
        if (m_stopLatestValue == 0 && value > 0)
×
1459
        {
1460
            slotStop();
×
1461
            m_stopLatestValue = value;
×
1462
        }
1463
        else if (m_stopLatestValue > HYSTERESIS && value == 0)
×
1464
        {
1465
            m_stopLatestValue = 0;
×
1466
        }
1467

1468
        if (value > HYSTERESIS)
×
1469
            m_stopLatestValue = value;
×
1470
    }
1471
    else if (checkInputSource(universe, pagedCh, value, sender(), sideFaderInputSourceId))
4✔
1472
    {
1473
        if (sideFaderMode() == None)
×
1474
            return;
×
1475

1476
        float val = SCALE((float) value, (float) 0, (float) UCHAR_MAX,
×
1477
                          (float) m_sideFader->minimum(),
1478
                          (float) m_sideFader->maximum());
1479
        m_sideFader->setValue(val);
×
1480
    }
1481
}
1482

1483
/*****************************************************************************
1484
 * VCWidget-inherited methods
1485
 *****************************************************************************/
1486

1487
void VCCueList::adjustIntensity(qreal val)
×
1488
{
1489
    Chaser *ch = chaser();
×
1490
    if (ch != NULL)
×
1491
    {
1492
        adjustFunctionIntensity(ch, val);
×
1493
/*
1494
        // Refresh intensity of current steps
1495
        if (!ch->stopped() && sideFaderMode() == Crossfade && m_sideFader->value() != 100)
1496
        {
1497
                ch->adjustStepIntensity((qreal)m_sideFader->value() / 100, m_primaryTop ? m_primaryIndex : m_secondaryIndex);
1498
                ch->adjustStepIntensity((qreal)(100 - m_sideFader->value()) / 100, m_primaryTop ? m_secondaryIndex : m_primaryIndex);
1499
        }
1500
*/
1501
    }
1502

1503
    VCWidget::adjustIntensity(val);
×
1504
}
×
1505

1506
void VCCueList::setCaption(const QString& text)
20✔
1507
{
1508
    VCWidget::setCaption(text);
20✔
1509

1510
    QStringList list;
20✔
1511
    list << "#" << text << tr("Fade In") << tr("Fade Out") << tr("Duration") << tr("Notes");
20✔
1512
    m_tree->setHeaderLabels(list);
20✔
1513
}
20✔
1514

1515
void VCCueList::setFont(const QFont& font)
1✔
1516
{
1517
    VCWidget::setFont(font);
1✔
1518

1519
    QFontMetrics m_fm = QFontMetrics(font);
1✔
1520
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
1521
    int w = m_fm.width("100%");
1522
#else
1523
    int w = m_fm.horizontalAdvance("100%");
1✔
1524
#endif
1525
    m_topPercentageLabel->setFixedWidth(w);
1✔
1526
    m_bottomPercentageLabel->setFixedWidth(w);
1✔
1527
}
1✔
1528

1529
void VCCueList::slotModeChanged(Doc::Mode mode)
23✔
1530
{
1531
    bool enable = false;
23✔
1532
    if (mode == Doc::Operate)
23✔
1533
    {
1534
        m_progress->setStyleSheet(progressFadeStyle);
6✔
1535
        m_progress->setRange(0, m_progress->width());
6✔
1536
        enable = true;
6✔
1537
        // send the initial feedback for the current step slider
1538
        updateFeedback();
6✔
1539
    }
1540
    else
1541
    {
1542
        m_topStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1543
        m_topStepLabel->setText("");
17✔
1544
        m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1545
        m_bottomStepLabel->setText("");
17✔
1546
        m_progress->setStyleSheet(progressDisabledStyle);
17✔
1547
        // reset any previously set background
1548
        QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
17✔
1549
        if (item != NULL)
17✔
1550
            item->setBackground(COL_NUM, m_defCol);
2✔
1551
    }
1552

1553
    enableWidgetUI(enable);
23✔
1554

1555
    /* Always start from the beginning */
1556
    m_tree->setCurrentItem(NULL);
23✔
1557

1558
    VCWidget::slotModeChanged(mode);
23✔
1559

1560
    emit sideFaderValueChanged();
23✔
1561
}
23✔
1562

1563
void VCCueList::editProperties()
×
1564
{
1565
    VCCueListProperties prop(this, m_doc);
×
1566
    if (prop.exec() == QDialog::Accepted)
×
1567
        m_doc->setModified();
×
1568
}
×
1569

1570
void VCCueList::playCueAtIndex(int idx)
4✔
1571
{
1572
    if (mode() != Doc::Operate)
4✔
1573
        return;
×
1574

1575
    m_primaryIndex = idx;
4✔
1576

1577
    Chaser *ch = chaser();
4✔
1578
    if (ch == NULL)
4✔
1579
        return;
×
1580

1581
    if (ch->isRunning())
4✔
1582
    {
1583
        ChaserAction action;
1584
        action.m_action = ChaserSetStepIndex;
3✔
1585
        action.m_stepIndex = m_primaryIndex;
3✔
1586
        action.m_masterIntensity = intensity();
3✔
1587
        action.m_stepIntensity = getPrimaryIntensity();
3✔
1588
        action.m_fadeMode = getFadeMode();
3✔
1589
        ch->setAction(action);
3✔
1590
    }
1591
    else
1592
    {
1593
        startChaser(m_primaryIndex);
1✔
1594
    }
1595

1596
    if (sideFaderMode() == Crossfade)
4✔
1597
        setFaderInfo(m_primaryIndex);
×
1598
}
1599

1600
FunctionParent VCCueList::functionParent() const
4✔
1601
{
1602
    return FunctionParent(FunctionParent::ManualVCWidget, id());
4✔
1603
}
1604

1605
/*****************************************************************************
1606
 * Load & Save
1607
 *****************************************************************************/
1608

1609
bool VCCueList::loadXML(QXmlStreamReader &root)
3✔
1610
{
1611
    QList <quint32> legacyStepList;
3✔
1612

1613
    if (root.name() != KXMLQLCVCCueList)
3✔
1614
    {
1615
        qWarning() << Q_FUNC_INFO << "CueList node not found";
1✔
1616
        return false;
1✔
1617
    }
1618

1619
    /* Widget commons */
1620
    loadXMLCommon(root);
2✔
1621

1622
    /* Children */
1623
    while (root.readNextStartElement())
18✔
1624
    {
1625
        if (root.name() == KXMLQLCWindowState)
16✔
1626
        {
1627
            bool visible = false;
1✔
1628
            int x = 0, y = 0, w = 0, h = 0;
1✔
1629
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
1✔
1630
            setGeometry(x, y, w, h);
1✔
1631
        }
1632
        else if (root.name() == KXMLQLCVCWidgetAppearance)
15✔
1633
        {
1634
            loadXMLAppearance(root);
1✔
1635
        }
1636
        else if (root.name() == KXMLQLCVCCueListNext)
14✔
1637
        {
1638
            QString str = loadXMLSources(root, nextInputSourceId);
1✔
1639
            if (str.isEmpty() == false)
1✔
1640
                m_nextKeySequence = stripKeySequence(QKeySequence(str));
1✔
1641
        }
1✔
1642
        else if (root.name() == KXMLQLCVCCueListPrevious)
13✔
1643
        {
1644
            QString str = loadXMLSources(root, previousInputSourceId);
1✔
1645
            if (str.isEmpty() == false)
1✔
1646
                m_previousKeySequence = stripKeySequence(QKeySequence(str));
1✔
1647
        }
1✔
1648
        else if (root.name() == KXMLQLCVCCueListPlayback)
12✔
1649
        {
1650
            QString str = loadXMLSources(root, playbackInputSourceId);
1✔
1651
            if (str.isEmpty() == false)
1✔
1652
                m_playbackKeySequence = stripKeySequence(QKeySequence(str));
1✔
1653
        }
1✔
1654
        else if (root.name() == KXMLQLCVCCueListStop)
11✔
1655
        {
1656
            QString str = loadXMLSources(root, stopInputSourceId);
1✔
1657
            if (str.isEmpty() == false)
1✔
1658
                m_stopKeySequence = stripKeySequence(QKeySequence(str));
1✔
1659
        }
1✔
1660
        else if (root.name() == KXMLQLCVCCueListSlidersMode)
10✔
1661
        {
1662
            setSideFaderMode(stringToFaderMode(root.readElementText()));
×
1663
        }
1664
        else if (root.name() == KXMLQLCVCCueListCrossfadeLeft)
10✔
1665
        {
1666
            loadXMLSources(root, sideFaderInputSourceId);
×
1667
        }
1668
        else if (root.name() == KXMLQLCVCCueListCrossfadeRight) /* Legacy */
10✔
1669
        {
1670
            root.skipCurrentElement();
×
1671
        }
1672
        else if (root.name() == KXMLQLCVCWidgetKey) /* Legacy */
10✔
1673
        {
1674
            setNextKeySequence(QKeySequence(root.readElementText()));
×
1675
        }
1676
        else if (root.name() == KXMLQLCVCCueListChaser)
10✔
1677
        {
1678
            setChaser(root.readElementText().toUInt());
×
1679
        }
1680
        else if (root.name() == KXMLQLCVCCueListPlaybackLayout)
10✔
1681
        {
1682
            PlaybackLayout layout = PlaybackLayout(root.readElementText().toInt());
×
1683
            if (layout != PlayPauseStop && layout != PlayStopPause)
×
1684
            {
1685
                qWarning() << Q_FUNC_INFO << "Playback layout" << layout << "does not exist.";
×
1686
                layout = PlayPauseStop;
×
1687
            }
1688
            setPlaybackLayout(layout);
×
1689
        }
1690
        else if (root.name() == KXMLQLCVCCueListNextPrevBehavior)
10✔
1691
        {
1692
            NextPrevBehavior nextPrev = NextPrevBehavior(root.readElementText().toInt());
×
1693
            if (nextPrev != DefaultRunFirst
×
1694
                    && nextPrev != RunNext
×
1695
                    && nextPrev != Select
×
1696
                    && nextPrev != Nothing)
×
1697
            {
1698
                qWarning() << Q_FUNC_INFO << "Next/Prev behavior" << nextPrev << "does not exist.";
×
1699
                nextPrev = DefaultRunFirst;
×
1700
            }
1701
            setNextPrevBehavior(nextPrev);
×
1702
        }
1703
        else if (root.name() == KXMLQLCVCCueListCrossfade)
10✔
1704
        {
1705
            m_crossfadeButton->setChecked(true);
×
1706
            root.skipCurrentElement();
×
1707
        }
1708
        else if (root.name() == KXMLQLCVCCueListFunction)
10✔
1709
        {
1710
            // Collect legacy file format steps into a list
1711
            legacyStepList << root.readElementText().toUInt();
6✔
1712
        }
1713
        else
1714
        {
1715
            qWarning() << Q_FUNC_INFO << "Unknown cuelist tag:" << root.name().toString();
4✔
1716
            root.skipCurrentElement();
4✔
1717
        }
1718
    }
1719

1720
    if (legacyStepList.isEmpty() == false)
2✔
1721
    {
1722
        /* Construct a new chaser from legacy step functions and use that chaser */
1723
        Chaser *chaser = new Chaser(m_doc);
1✔
1724
        chaser->setName(caption());
1✔
1725

1726
        // Legacy cue lists relied on individual functions' timings and a common hold time
1727
        chaser->setFadeInMode(Chaser::Default);
1✔
1728
        chaser->setFadeOutMode(Chaser::Default);
1✔
1729
        chaser->setDurationMode(Chaser::Common);
1✔
1730

1731
        foreach (quint32 id, legacyStepList)
7✔
1732
        {
1733
            Function *function = m_doc->function(id);
6✔
1734
            if (function == NULL)
6✔
1735
                continue;
2✔
1736

1737
            // Legacy cuelists relied on individual functions' fadein/out speed and
1738
            // infinite duration. So don't touch them at all.
1739
            ChaserStep step(id);
4✔
1740
            chaser->addStep(step);
4✔
1741
        }
5✔
1742

1743
        // Add the chaser to Doc and attach it to the cue list
1744
        m_doc->addFunction(chaser);
1✔
1745
        setChaser(chaser->id());
1✔
1746
    }
1747

1748
    return true;
2✔
1749
}
3✔
1750

1751
bool VCCueList::saveXML(QXmlStreamWriter *doc)
1✔
1752
{
1753
    Q_ASSERT(doc != NULL);
1✔
1754

1755
    /* VC CueList entry */
1756
    doc->writeStartElement(KXMLQLCVCCueList);
2✔
1757

1758
    saveXMLCommon(doc);
1✔
1759

1760
    /* Window state */
1761
    saveXMLWindowState(doc);
1✔
1762

1763
    /* Appearance */
1764
    saveXMLAppearance(doc);
1✔
1765

1766
    /* Chaser */
1767
    doc->writeTextElement(KXMLQLCVCCueListChaser, QString::number(chaserID()));
2✔
1768

1769
    /* Playback layout */
1770
    if (playbackLayout() != PlayPauseStop)
1✔
1771
        doc->writeTextElement(KXMLQLCVCCueListPlaybackLayout, QString::number(playbackLayout()));
×
1772

1773
    /* Next/Prev behavior */
1774
    doc->writeTextElement(KXMLQLCVCCueListNextPrevBehavior, QString::number(nextPrevBehavior()));
2✔
1775

1776
    /* Next cue */
1777
    doc->writeStartElement(KXMLQLCVCCueListNext);
2✔
1778
    if (m_nextKeySequence.toString().isEmpty() == false)
1✔
1779
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_nextKeySequence.toString());
2✔
1780
    saveXMLInput(doc, inputSource(nextInputSourceId));
1✔
1781
    doc->writeEndElement();
1✔
1782

1783
    /* Previous cue */
1784
    doc->writeStartElement(KXMLQLCVCCueListPrevious);
2✔
1785
    if (m_previousKeySequence.toString().isEmpty() == false)
1✔
1786
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_previousKeySequence.toString());
2✔
1787
    saveXMLInput(doc, inputSource(previousInputSourceId));
1✔
1788
    doc->writeEndElement();
1✔
1789

1790
    /* Cue list playback */
1791
    doc->writeStartElement(KXMLQLCVCCueListPlayback);
2✔
1792
    if (m_playbackKeySequence.toString().isEmpty() == false)
1✔
1793
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_playbackKeySequence.toString());
2✔
1794
    saveXMLInput(doc, inputSource(playbackInputSourceId));
1✔
1795
    doc->writeEndElement();
1✔
1796

1797
    /* Cue list stop */
1798
    doc->writeStartElement(KXMLQLCVCCueListStop);
2✔
1799
    if (m_stopKeySequence.toString().isEmpty() == false)
1✔
1800
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_stopKeySequence.toString());
2✔
1801
    saveXMLInput(doc, inputSource(stopInputSourceId));
1✔
1802
    doc->writeEndElement();
1✔
1803

1804
    /* Crossfade cue list */
1805
    if (sideFaderMode() != None)
1✔
1806
        doc->writeTextElement(KXMLQLCVCCueListSlidersMode, faderModeToString(sideFaderMode()));
2✔
1807

1808
    QSharedPointer<QLCInputSource> cf1Src = inputSource(sideFaderInputSourceId);
1✔
1809
    if (!cf1Src.isNull() && cf1Src->isValid())
1✔
1810
    {
1811
        doc->writeStartElement(KXMLQLCVCCueListCrossfadeLeft);
×
1812
        saveXMLInput(doc, cf1Src);
×
1813
        doc->writeEndElement();
×
1814
    }
1815

1816
    /* End the <CueList> tag */
1817
    doc->writeEndElement();
1✔
1818

1819
    return true;
1✔
1820
}
1✔
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