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

mcallegari / qlcplus / 26300346302

22 May 2026 04:44PM UTC coverage: 35.037%. Remained the same
26300346302

Pull #2030

github

web-flow
Merge f6fded169 into 8db411f5d
Pull Request #2030: replace tab stops with spaces and remove trailing whitespace characters

8 of 53 new or added lines in 10 files covered. (15.09%)

3 existing lines in 1 file now uncovered.

18293 of 52211 relevant lines covered (35.04%)

41158.63 hits per line

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

62.02
/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)
16✔
88
    , m_chaserID(Function::invalidId())
32✔
89
    , m_nextPrevBehavior(DefaultRunFirst)
16✔
90
    , m_playbackLayout(PlayPauseStop)
16✔
91
    , m_timer(NULL)
16✔
92
    , m_primaryIndex(0)
16✔
93
    , m_secondaryIndex(0)
16✔
94
    , m_primaryTop(true)
16✔
95
    , m_slidersMode(None)
16✔
96
{
97
    /* Set the class name "VCCueList" as the object name as well */
98
    setObjectName(VCCueList::staticMetaObject.className());
16✔
99

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

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

106
    m_topPercentageLabel = new QLabel("100%");
16✔
107
    m_topPercentageLabel->setAlignment(Qt::AlignHCenter);
16✔
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%"));
16✔
112
#endif
113
    grid->addWidget(m_topPercentageLabel, 1, 0, 1, 1);
16✔
114

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

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

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

134
    m_bottomPercentageLabel = new QLabel("0%");
16✔
135
    m_bottomPercentageLabel->setAlignment(Qt::AlignHCenter);
16✔
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%"));
16✔
140
#endif
141
    grid->addWidget(m_bottomPercentageLabel, 5, 0, 1, 1);
16✔
142

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

146
    slotShowCrossfadePanel(false);
16✔
147

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

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

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

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

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

184
    m_timer = new QTimer(this);
16✔
185
    connect(m_timer, SIGNAL(timeout()),
16✔
186
            this, SLOT(slotProgressTimeout()));
187

188
    m_updateTimer = new QTimer(this);
16✔
189
    connect(m_updateTimer, SIGNAL(timeout()),
16✔
190
            this, SLOT(slotUpdateStepList()));
191
    m_updateTimer->setSingleShot(true);
16✔
192

193
    /* Create control buttons */
194
    QHBoxLayout *hbox = new QHBoxLayout();
16✔
195
    hbox->setSpacing(2);
16✔
196

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

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

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

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

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

245
    vbox->addItem(hbox);
16✔
246
    grid->addItem(vbox, 0, 1, 6);
16✔
247

248
    setFrameStyle(KVCFrameStyleSunken);
16✔
249
    setType(VCWidget::CueListWidget);
16✔
250
    setCaption(tr("Cue list"));
16✔
251

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

259
    slotModeChanged(m_doc->mode());
16✔
260
    setLiveEdit(m_liveEdit);
16✔
261

262
    connect(m_doc, SIGNAL(functionRemoved(quint32)),
16✔
263
            this, SLOT(slotFunctionRemoved(quint32)));
264
    connect(m_doc, SIGNAL(functionChanged(quint32)),
16✔
265
            this, SLOT(slotFunctionChanged(quint32)));
266
    connect(m_doc, SIGNAL(functionNameChanged(quint32)),
16✔
267
            this, SLOT(slotFunctionNameChanged(quint32)));
268

269
    m_nextLatestValue = 0;
16✔
270
    m_previousLatestValue = 0;
16✔
271
    m_playbackLatestValue = 0;
16✔
272
    m_stopLatestValue = 0;
16✔
273
}
16✔
274

275
VCCueList::~VCCueList()
19✔
276
{
277
}
19✔
278

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

287
    m_topPercentageLabel->setEnabled(enable);
27✔
288
    m_sideFader->setEnabled(enable);
27✔
289
    m_topStepLabel->setEnabled(enable);
27✔
290
    m_bottomPercentageLabel->setEnabled(enable);
27✔
291
    m_bottomStepLabel->setEnabled(enable);
27✔
292
}
27✔
293

294
/*****************************************************************************
295
 * Clipboard
296
 *****************************************************************************/
297

298
VCWidget *VCCueList::createCopy(VCWidget *parent) const
1✔
299
{
300
    Q_ASSERT(parent != NULL);
1✔
301

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

309
    return cuelist;
1✔
310
}
311

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

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

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

327
    /* Sliders mode */
328
    setSideFaderMode(cuelist->sideFaderMode());
2✔
329

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

334
/*****************************************************************************
335
 * Cue list
336
 *****************************************************************************/
337

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

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

363
        m_chaserID = id;
12✔
364
    }
365
    else
366
    {
367
        m_chaserID = Function::invalidId();
3✔
368
    }
369

370
    updateStepList();
15✔
371

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

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

387
Chaser *VCCueList::chaser() const
116✔
388
{
389
    if (m_chaserID == Function::invalidId())
116✔
390
        return NULL;
7✔
391
    Chaser *chaser = qobject_cast<Chaser*>(m_doc->function(m_chaserID));
109✔
392
    return chaser;
109✔
393
}
394

395
void VCCueList::updateStepList()
16✔
396
{
397
    m_listIsUpdating = true;
16✔
398

399
    m_tree->clear();
16✔
400

401
    Chaser *ch = chaser();
16✔
402
    if (ch == NULL)
16✔
403
        return;
3✔
404

405
    QListIterator <ChaserStep> it(ch->steps());
13✔
406
    while (it.hasNext() == true)
61✔
407
    {
408
        ChaserStep step(it.next());
48✔
409

410
        Function *function = m_doc->function(step.fid);
48✔
411
        Q_ASSERT(function != NULL);
48✔
412

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

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

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

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

462
    QTreeWidgetItem *item = m_tree->topLevelItem(0);
13✔
463
    if (item != NULL)
13✔
464
        m_defCol = item->background(COL_NUM);
13✔
465

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

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

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

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

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

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

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

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

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

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

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

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

543
int VCCueList::getFirstTreeIndex() const
3✔
544
{
545
    return 0;
3✔
546
}
547

548
int VCCueList::getLastTreeIndex() const
×
549
{
550
    return m_tree->topLevelItemCount() - 1;
×
551
}
552

553
qreal VCCueList::getPrimaryIntensity() const
22✔
554
{
555
    if (sideFaderMode() == Steps)
22✔
556
        return  1.0;
×
557

558
    return m_primaryTop ? qreal(m_sideFader->value() / 100.0) : qreal((100 - m_sideFader->value()) / 100.0);
22✔
559
}
560

561
void VCCueList::notifyFunctionStarting(quint32 fid, qreal intensity, bool excludeMonitored)
×
562
{
563
    Q_UNUSED(intensity)
564
    Q_UNUSED(excludeMonitored)
565

566
    if (mode() == Doc::Design)
×
567
        return;
×
568

569
    if (fid == m_chaserID)
×
570
        return;
×
571

572
    stopChaser();
×
573
}
574

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

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

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

611
void VCCueList::slotUpdateStepList()
1✔
612
{
613
    updateStepList();
1✔
614
}
1✔
615

616
void VCCueList::slotPlayback()
4✔
617
{
618
    if (mode() != Doc::Operate)
4✔
619
        return;
×
620

621
    Chaser *ch = chaser();
4✔
622
    if (ch == NULL)
4✔
623
        return;
×
624

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

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

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

663
    emit playbackButtonClicked();
4✔
664
}
665

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

671
    Chaser *ch = chaser();
×
672
    if (ch == NULL)
×
673
        return;
×
674

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

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

708
    emit stopButtonClicked();
×
709
}
710

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

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

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

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

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

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

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

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

821
        float stepVal;
822
        int stepsCount = m_tree->topLevelItemCount();
×
NEW
823
        if (stepsCount < 256)
×
824
        {
825
            stepVal = 256.0 / (float)stepsCount; //divide up the full 0..255 range
×
826
            stepVal = qFloor((stepVal * 100000.0) + 0.5) / 100000.0; //round to 5 decimals to fix corner cases
×
827
        }
828
        else
829
        {
830
            stepVal = 1.0;
×
831
        }
832

833
        // value->step# truncates down in slotSideFaderValueChanged; so use ceiling for step#->value
834
        float slValue = stepVal * (float)stepNumber;
×
835
        if (slValue > 255)
×
836
            slValue = 255.0;
×
837

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

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

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

868
    playCueAtIndex(m_tree->indexOfTopLevelItem(item));
4✔
869
}
870

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

876
    Chaser *ch = chaser();
×
877
    if (ch == NULL)
×
878
        return;
×
879

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

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

887
    emit stepNoteChanged(idx, itemText);
×
888
}
×
889

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

900
void VCCueList::slotItemDoubleClicked(QTreeWidgetItem *item, int column)
×
901
{
902
    Q_UNUSED(column)
903

904
    if (mode() != Doc::Operate)
×
905
        return;
×
906

907
    playCueAtIndex(m_tree->indexOfTopLevelItem(item));
×
908
}
909

910
void VCCueList::slotFunctionRunning(quint32 fid)
6✔
911
{
912
    if (fid != m_chaserID)
6✔
913
        return;
×
914

915
    if (playbackLayout() == PlayPauseStop)
6✔
916
        m_playbackButton->setIcon(QIcon(":/player_pause.png"));
6✔
917
    else if (playbackLayout() == PlayStopPause)
×
918
        m_playbackButton->setIcon(QIcon(":/player_stop.png"));
×
919
    m_timer->start(PROGRESS_INTERVAL);
6✔
920
    emit playbackStatusChanged();
6✔
921
    updateFeedback();
6✔
922
}
923

924
void VCCueList::slotFunctionStopped(quint32 fid)
16✔
925
{
926
    if (fid != m_chaserID)
16✔
927
        return;
×
928

929
    resetIntensityOverrideAttribute();
16✔
930
    m_playbackButton->setIcon(QIcon(":/player_play.png"));
16✔
931
    m_topStepLabel->setText("");
16✔
932
    m_topStepLabel->setStyleSheet(cfLabelNoStyle);
16✔
933
    m_bottomStepLabel->setText("");
16✔
934
    m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
16✔
935
    // reset any previously set background
936
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
16✔
937
    if (item != NULL)
16✔
938
        item->setBackground(COL_NUM, m_defCol);
13✔
939

940
    emit stepChanged(-1);
16✔
941

942
    m_progress->setFormat("");
16✔
943
    m_progress->setValue(0);
16✔
944

945
    emit progressStateChanged();
16✔
946
    emit sideFaderValueChanged();
16✔
947
    emit playbackStatusChanged();
16✔
948

949
    qDebug() << Q_FUNC_INFO << "Cue stopped";
16✔
950
    updateFeedback();
16✔
951
}
952

953
void VCCueList::slotProgressTimeout()
×
954
{
955
    Chaser *ch = chaser();
×
956
    if (ch == NULL || !ch->isRunning())
×
957
        return;
×
958

959
    ChaserRunnerStep step(ch->currentRunningStep());
×
960
    if (step.m_function != NULL)
×
961
    {
962
        int status = m_progress->property("status").toInt();
×
963
        int newstatus;
964
        if (step.m_fadeIn == Function::defaultSpeed())
×
965
            newstatus = 1;
×
966
        else if (step.m_elapsed > (quint32)step.m_fadeIn)
×
967
            newstatus = 1;
×
968
        else
969
            newstatus = 0;
×
970

971
        if (newstatus != status)
×
972
        {
973
            if (newstatus == 0)
×
974
                m_progress->setStyleSheet(progressFadeStyle);
×
975
            else
976
                m_progress->setStyleSheet(progressHoldStyle);
×
977
            m_progress->setProperty("status", newstatus);
×
978
        }
979
        if (step.m_duration == Function::infiniteSpeed())
×
980
        {
981
            if (newstatus == 0 && step.m_fadeIn != Function::defaultSpeed())
×
982
            {
983
                double progress = ((double)step.m_elapsed / (double)step.m_fadeIn) * (double)m_progress->width();
×
984
                m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_fadeIn - step.m_elapsed)));
×
985
                m_progress->setValue(progress);
×
986

987
                emit progressStateChanged();
×
988
            }
989
            else
990
            {
991
                m_progress->setValue(m_progress->maximum());
×
992
                m_progress->setFormat("");
×
993

994
                emit progressStateChanged();
×
995
            }
996
            return;
×
997
        }
998
        else
999
        {
1000
            double progress = ((double)step.m_elapsed / (double)step.m_duration) * (double)m_progress->width();
×
1001
            m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_duration - step.m_elapsed)));
×
1002
            m_progress->setValue(progress);
×
1003

1004
            emit progressStateChanged();
×
1005
        }
1006
    }
1007
    else
1008
    {
1009
        m_progress->setValue(0);
×
1010
    }
1011
}
1012

1013
QString VCCueList::progressText() const
×
1014
{
1015
    return m_progress->text();
×
1016
}
1017

1018
double VCCueList::progressPercent() const
×
1019
{
1020
    return ((double)m_progress->value() * 100) / (double)m_progress->width();
×
1021
}
1022

1023
void VCCueList::startChaser(int startIndex)
6✔
1024
{
1025
    Chaser *ch = chaser();
6✔
1026
    if (ch == NULL)
6✔
1027
        return;
×
1028

1029
    adjustFunctionIntensity(ch, intensity());
6✔
1030

1031
    ChaserAction action;
1032
    action.m_action = ChaserSetStepIndex;
6✔
1033
    action.m_stepIndex = startIndex;
6✔
1034
    action.m_masterIntensity = intensity();
6✔
1035
    action.m_stepIntensity = getPrimaryIntensity();
6✔
1036
    action.m_fadeMode = getFadeMode();
6✔
1037
    ch->setAction(action);
6✔
1038

1039
    ch->start(m_doc->masterTimer(), functionParent());
6✔
1040
    emit functionStarting(m_chaserID);
6✔
1041
}
1042

1043
void VCCueList::stopChaser()
×
1044
{
1045
    Chaser *ch = chaser();
×
1046
    if (ch == NULL)
×
1047
        return;
×
1048

1049
    ch->stop(functionParent());
×
1050
    resetIntensityOverrideAttribute();
×
1051
}
1052

1053
int VCCueList::getFadeMode() const
22✔
1054
{
1055
    if (sideFaderMode() != Crossfade)
22✔
1056
        return Chaser::FromFunction;
20✔
1057

1058
    if (m_sideFader->value() != 0 && m_sideFader->value() != 100)
2✔
1059
        return Chaser::BlendedCrossfade;
×
1060

1061
    return Chaser::Blended;
2✔
1062
}
1063

1064
void VCCueList::setNextPrevBehavior(NextPrevBehavior nextPrev)
×
1065
{
1066
    Q_ASSERT(nextPrev == DefaultRunFirst
×
1067
            || nextPrev == RunNext
1068
            || nextPrev == Select
1069
            || nextPrev == Nothing);
1070
    m_nextPrevBehavior = nextPrev;
×
1071
}
×
1072

1073
VCCueList::NextPrevBehavior VCCueList::nextPrevBehavior() const
1✔
1074
{
1075
    return m_nextPrevBehavior;
1✔
1076
}
1077

1078
void VCCueList::setPlaybackLayout(VCCueList::PlaybackLayout layout)
×
1079
{
1080
    if (layout == m_playbackLayout)
×
1081
        return;
×
1082

1083
    if (layout == PlayStopPause)
×
1084
    {
1085
        m_stopButton->setIcon(QIcon(":/player_pause.png"));
×
1086
        m_playbackButton->setToolTip(tr("Play/Stop Cue list"));
×
1087
        m_stopButton->setToolTip(tr("Pause Cue list"));
×
1088
    }
1089
    else if (layout == PlayPauseStop)
×
1090
    {
1091
        m_stopButton->setIcon(QIcon(":/player_stop.png"));
×
1092
        m_playbackButton->setToolTip(tr("Play/Pause Cue list"));
×
1093
        m_stopButton->setToolTip(tr("Stop Cue list"));
×
1094
    }
1095
    else
1096
    {
1097
        qWarning() << "Playback layout" << layout << "doesn't exist!";
×
1098
        layout = PlayPauseStop;
×
1099
    }
1100

1101
    m_playbackLayout = layout;
×
1102
}
1103

1104
VCCueList::PlaybackLayout VCCueList::playbackLayout() const
9✔
1105
{
1106
    return m_playbackLayout;
9✔
1107
}
1108

1109
VCCueList::FaderMode VCCueList::sideFaderMode() const
73✔
1110
{
1111
    return m_slidersMode;
73✔
1112
}
1113

1114
void VCCueList::setSideFaderMode(VCCueList::FaderMode mode)
4✔
1115
{
1116
    m_slidersMode = mode;
4✔
1117

1118
    bool show = (mode == None) ? false : true;
4✔
1119
    m_crossfadeButton->setVisible(show);
4✔
1120
    m_topPercentageLabel->setVisible(show);
4✔
1121
    m_topStepLabel->setVisible(mode == Steps ? false : show);
4✔
1122
    m_sideFader->setVisible(show);
4✔
1123
    m_bottomPercentageLabel->setVisible(mode == Steps ? false : show);
4✔
1124
    m_bottomStepLabel->setVisible(show);
4✔
1125
    m_sideFader->setMaximum(mode == Steps ? 255 : 100);
4✔
1126
    m_sideFader->setValue(mode == Steps ? 255 : 100);
4✔
1127
}
4✔
1128

1129
VCCueList::FaderMode VCCueList::stringToFaderMode(QString modeStr) const
×
1130
{
1131
    if (modeStr == "Crossfade")
×
1132
        return Crossfade;
×
1133
    else if (modeStr == "Steps")
×
1134
        return Steps;
×
1135

1136
    return None;
×
1137
}
1138

1139
QString VCCueList::faderModeToString(VCCueList::FaderMode mode) const
1✔
1140
{
1141
    if (mode == Crossfade)
1✔
1142
        return "Crossfade";
1✔
1143
    else if (mode == Steps)
×
1144
        return "Steps";
×
1145

1146
    return "None";
×
1147
}
1148

1149
/*****************************************************************************
1150
 * Crossfade
1151
 *****************************************************************************/
1152
void VCCueList::setFaderInfo(int index)
21✔
1153
{
1154
    Chaser *ch = chaser();
21✔
1155
    if (ch == NULL || !ch->isRunning())
21✔
1156
        return;
×
1157

1158
    int tmpIndex = ch->computeNextStep(index);
21✔
1159

1160
    m_topStepLabel->setText(QString("#%1").arg(m_primaryTop ? index + 1 : tmpIndex + 1));
21✔
1161
    m_topStepLabel->setStyleSheet(m_primaryTop ? cfLabelBlueStyle : cfLabelOrangeStyle);
21✔
1162

1163
    m_bottomStepLabel->setText(QString("#%1").arg(m_primaryTop ? tmpIndex + 1 : index + 1));
21✔
1164
    m_bottomStepLabel->setStyleSheet(m_primaryTop ? cfLabelOrangeStyle : cfLabelBlueStyle);
21✔
1165

1166
    // reset any previously set background
1167
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
21✔
1168
    if (item != NULL)
21✔
1169
        item->setBackground(COL_NUM, m_defCol);
21✔
1170

1171
    item = m_tree->topLevelItem(tmpIndex);
21✔
1172
    if (item != NULL)
21✔
1173
        item->setBackground(COL_NUM, QColor("#FF8000"));
21✔
1174
    m_secondaryIndex = tmpIndex;
21✔
1175

1176
    emit sideFaderValueChanged();
21✔
1177
}
1178

1179
void VCCueList::slotShowCrossfadePanel(bool enable)
16✔
1180
{
1181
    m_topPercentageLabel->setVisible(enable);
16✔
1182
    m_topStepLabel->setVisible(enable);
16✔
1183
    m_sideFader->setVisible(enable);
16✔
1184
    m_bottomStepLabel->setVisible(enable);
16✔
1185
    m_bottomPercentageLabel->setVisible(enable);
16✔
1186

1187
    emit sideFaderButtonToggled();
16✔
1188
}
16✔
1189

1190
QString VCCueList::topPercentageValue() const
×
1191
{
1192
    return m_topPercentageLabel->text();
×
1193
}
1194

1195
QString VCCueList::bottomPercentageValue() const
×
1196
{
1197
    return m_bottomPercentageLabel->text();
×
1198
}
1199

1200
QString VCCueList::topStepValue() const
×
1201
{
1202
    return m_topStepLabel->text();
×
1203
}
1204

1205
QString VCCueList::bottomStepValue() const
×
1206
{
1207
    return m_bottomStepLabel->text();
×
1208
}
1209

1210
int VCCueList::sideFaderValue() const
×
1211
{
1212
    return m_sideFader->value();
×
1213
}
1214

1215
bool VCCueList::primaryTop() const
×
1216
{
1217
    return m_primaryTop;
×
1218
}
1219

1220
void VCCueList::slotSideFaderButtonChecked(bool enable)
×
1221
{
1222
    m_crossfadeButton->setChecked(enable);
×
1223
    emit sideFaderButtonChecked();
×
1224
}
×
1225

1226
bool VCCueList::isSideFaderVisible() const
×
1227
{
1228
    return m_sideFader->isVisible();
×
1229
}
1230

1231
bool VCCueList::sideFaderButtonIsChecked() const
×
1232
{
1233
    return m_crossfadeButton->isChecked();
×
1234
}
1235

1236
void VCCueList::slotSetSideFaderValue(int value)
×
1237
{
1238
    m_sideFader->setValue(value);
×
1239
}
×
1240

1241
void VCCueList::slotSideFaderValueChanged(int value)
×
1242
{
1243
    if (sideFaderMode() == Steps)
×
1244
    {
1245
        value = 255 - value;
×
1246
        m_topPercentageLabel->setText(QString("%1").arg(value));
×
1247

1248
        emit sideFaderValueChanged();
×
1249

1250
        Chaser *ch = chaser();
×
1251
        if (ch == NULL || ch->stopped())
×
1252
            return;
×
1253

1254
        int newStep = value; // by default we assume the Chaser has more than 256 steps
×
1255
        if (ch->stepsCount() < 256)
×
1256
        {
1257
            float stepSize = 256.0 / (float)ch->stepsCount();  //divide up the full 0..255 range
×
1258
            stepSize = qFloor((stepSize * 100000.0) + 0.5) / 100000.0; //round to 5 decimals to fix corner cases
×
1259
            if (value >= 256.0 - stepSize)
×
1260
                newStep = ch->stepsCount() - 1;
×
1261
            else
1262
                newStep = qFloor((float)value / stepSize);
×
1263
            //qDebug() << "value:" << value << " new step:" << newStep << " stepSize:" << stepSize;
1264
        }
1265

1266
        if (newStep == ch->currentStepIndex())
×
1267
            return;
×
1268

1269
        ChaserAction action;
1270
        action.m_action = ChaserSetStepIndex;
×
1271
        action.m_stepIndex = newStep;
×
1272
        action.m_masterIntensity = intensity();
×
1273
        action.m_stepIntensity = getPrimaryIntensity();
×
1274
        action.m_fadeMode = getFadeMode();
×
1275
        ch->setAction(action);
×
1276
    }
1277
    else
1278
    {
1279
        m_topPercentageLabel->setText(QString("%1%").arg(value));
×
1280
        m_bottomPercentageLabel->setText(QString("%1%").arg(100 - value));
×
1281

1282
        emit sideFaderValueChanged();
×
1283

1284
        Chaser *ch = chaser();
×
1285
        if (!(ch == NULL || ch->stopped()))
×
1286
        {
1287
            ch->adjustStepIntensity(qreal(value) / 100.0, m_primaryTop ? m_primaryIndex : m_secondaryIndex,
×
1288
                                    Chaser::FadeControlMode(getFadeMode()));
×
1289
            ch->adjustStepIntensity(qreal(100 - value) / 100.0, m_primaryTop ? m_secondaryIndex : m_primaryIndex,
×
1290
                                    Chaser::FadeControlMode(getFadeMode()));
×
1291
            stopStepIfNeeded(ch);
×
1292
        }
1293
    }
1294

1295
    updateFeedback();
×
1296
}
1297

1298
void VCCueList::stopStepIfNeeded(Chaser *ch)
×
1299
{
1300
    if (ch->runningStepsNumber() != 2)
×
1301
        return;
×
1302

1303
    int primaryValue = m_primaryTop ? m_sideFader->value() : 100 - m_sideFader->value();
×
1304
    int secondaryValue = m_primaryTop ? 100 - m_sideFader->value() : m_sideFader->value();
×
1305

1306
    ChaserAction action;
1307
    action.m_action = ChaserStopStep;
×
1308

1309
    if (primaryValue == 0)
×
1310
    {
1311
        m_primaryTop = !m_primaryTop;
×
1312
        action.m_stepIndex = m_primaryIndex;
×
1313
        ch->setAction(action);
×
1314
    }
1315
    else if (secondaryValue == 0)
×
1316
    {
1317
        action.m_stepIndex = m_secondaryIndex;
×
1318
        ch->setAction(action);
×
1319
    }
1320
}
1321

1322
/*****************************************************************************
1323
 * Key Sequences
1324
 *****************************************************************************/
1325

1326
void VCCueList::setNextKeySequence(const QKeySequence& keySequence)
6✔
1327
{
1328
    m_nextKeySequence = QKeySequence(keySequence);
6✔
1329
}
6✔
1330

1331
QKeySequence VCCueList::nextKeySequence() const
8✔
1332
{
1333
    return m_nextKeySequence;
8✔
1334
}
1335

1336
void VCCueList::setPreviousKeySequence(const QKeySequence& keySequence)
6✔
1337
{
1338
    m_previousKeySequence = QKeySequence(keySequence);
6✔
1339
}
6✔
1340

1341
QKeySequence VCCueList::previousKeySequence() const
8✔
1342
{
1343
    return m_previousKeySequence;
8✔
1344
}
1345

1346
void VCCueList::setPlaybackKeySequence(const QKeySequence& keySequence)
6✔
1347
{
1348
    m_playbackKeySequence = QKeySequence(keySequence);
6✔
1349
}
6✔
1350

1351
QKeySequence VCCueList::playbackKeySequence() const
8✔
1352
{
1353
    return m_playbackKeySequence;
8✔
1354
}
1355

1356
void VCCueList::setStopKeySequence(const QKeySequence &keySequence)
3✔
1357
{
1358
    m_stopKeySequence = QKeySequence(keySequence);
3✔
1359
}
3✔
1360

1361
QKeySequence VCCueList::stopKeySequence() const
3✔
1362
{
1363
    return m_stopKeySequence;
3✔
1364
}
1365

1366
void VCCueList::slotKeyPressed(const QKeySequence& keySequence)
7✔
1367
{
1368
    if (acceptsInput() == false)
7✔
1369
        return;
×
1370

1371
    if (m_nextKeySequence == keySequence)
7✔
1372
        slotNextCue();
3✔
1373
    else if (m_previousKeySequence == keySequence)
4✔
1374
        slotPreviousCue();
2✔
1375
    else if (m_playbackKeySequence == keySequence)
2✔
1376
        slotPlayback();
1✔
1377
    else if (m_stopKeySequence == keySequence)
1✔
1378
        slotStop();
×
1379
}
1380

1381
void VCCueList::updateFeedback()
40✔
1382
{
1383
    int fbv = int(SCALE(float(m_sideFader->value()),
40✔
1384
                        float(m_sideFader->minimum()),
1385
                        float(m_sideFader->maximum()),
1386
                        float(0), float(UCHAR_MAX)));
40✔
1387
    sendFeedback(fbv, sideFaderInputSourceId);
40✔
1388

1389
    Chaser *ch = chaser();
40✔
1390
    if (ch == NULL)
40✔
1391
        return;
3✔
1392

1393
    sendFeedback(ch->isRunning() ? UCHAR_MAX : 0, playbackInputSourceId);
37✔
1394
}
1395

1396
/*****************************************************************************
1397
 * External Input
1398
 *****************************************************************************/
1399

1400
void VCCueList::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
12✔
1401
{
1402
    /* Don't let input data through in design mode or if disabled */
1403
    if (acceptsInput() == false)
12✔
1404
        return;
×
1405

1406
    quint32 pagedCh = (page() << 16) | channel;
12✔
1407

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

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

1443
        if (value > HYSTERESIS)
3✔
1444
            m_previousLatestValue = value;
2✔
1445
    }
1446
    else if (checkInputSource(universe, pagedCh, value, sender(), playbackInputSourceId))
6✔
1447
    {
1448
        // Use hysteresis for values, in case the cue list is being controlled
1449
        // by a slider. The value has to go to zero before the next non-zero
1450
        // value is accepted as input. And the non-zero values have to visit
1451
        // above $HYSTERESIS before a zero is accepted again.
1452
        if (m_playbackLatestValue == 0 && value > 0)
2✔
1453
        {
1454
            slotPlayback();
1✔
1455
            m_playbackLatestValue = value;
1✔
1456
        }
1457
        else if (m_playbackLatestValue > HYSTERESIS && value == 0)
1✔
1458
        {
1459
            m_playbackLatestValue = 0;
1✔
1460
        }
1461

1462
        if (value > HYSTERESIS)
2✔
1463
            m_playbackLatestValue = value;
1✔
1464
    }
1465
    else if (checkInputSource(universe, pagedCh, value, sender(), stopInputSourceId))
4✔
1466
    {
1467
        // Use hysteresis for values, in case the cue list is being controlled
1468
        // by a slider. The value has to go to zero before the next non-zero
1469
        // value is accepted as input. And the non-zero values have to visit
1470
        // above $HYSTERESIS before a zero is accepted again.
1471
        if (m_stopLatestValue == 0 && value > 0)
×
1472
        {
1473
            slotStop();
×
1474
            m_stopLatestValue = value;
×
1475
        }
1476
        else if (m_stopLatestValue > HYSTERESIS && value == 0)
×
1477
        {
1478
            m_stopLatestValue = 0;
×
1479
        }
1480

1481
        if (value > HYSTERESIS)
×
1482
            m_stopLatestValue = value;
×
1483
    }
1484
    else if (checkInputSource(universe, pagedCh, value, sender(), sideFaderInputSourceId))
4✔
1485
    {
1486
        if (sideFaderMode() == None)
×
1487
            return;
×
1488

1489
        float val = SCALE((float) value, (float) 0, (float) UCHAR_MAX,
×
1490
                          (float) m_sideFader->minimum(),
1491
                          (float) m_sideFader->maximum());
1492
        m_sideFader->setValue(val);
×
1493
    }
1494
}
1495

1496
/*****************************************************************************
1497
 * VCWidget-inherited methods
1498
 *****************************************************************************/
1499

1500
void VCCueList::adjustIntensity(qreal val)
6✔
1501
{
1502
    Chaser *ch = chaser();
6✔
1503
    if (ch != NULL)
6✔
1504
    {
1505
        adjustFunctionIntensity(ch, val);
5✔
1506
/*
1507
        // Refresh intensity of current steps
1508
        if (!ch->stopped() && sideFaderMode() == Crossfade && m_sideFader->value() != 100)
1509
        {
1510
                ch->adjustStepIntensity((qreal)m_sideFader->value() / 100, m_primaryTop ? m_primaryIndex : m_secondaryIndex);
1511
                ch->adjustStepIntensity((qreal)(100 - m_sideFader->value()) / 100, m_primaryTop ? m_secondaryIndex : m_primaryIndex);
1512
        }
1513
*/
1514
    }
1515

1516
    VCWidget::adjustIntensity(val);
6✔
1517
}
6✔
1518

1519
void VCCueList::setCaption(const QString& text)
21✔
1520
{
1521
    VCWidget::setCaption(text);
21✔
1522

1523
    QStringList list;
21✔
1524
    list << "#" << text << tr("Fade In") << tr("Fade Out") << tr("Duration") << tr("Notes");
21✔
1525
    m_tree->setHeaderLabels(list);
21✔
1526
}
21✔
1527

1528
void VCCueList::setFont(const QFont& font)
1✔
1529
{
1530
    VCWidget::setFont(font);
1✔
1531

1532
    QFontMetrics m_fm = QFontMetrics(font);
1✔
1533
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
1534
    int w = m_fm.width("100%");
1535
#else
1536
    int w = m_fm.horizontalAdvance("100%");
1✔
1537
#endif
1538
    m_topPercentageLabel->setFixedWidth(w);
1✔
1539
    m_bottomPercentageLabel->setFixedWidth(w);
1✔
1540
}
1✔
1541

1542
void VCCueList::slotModeChanged(Doc::Mode mode)
27✔
1543
{
1544
    bool enable = false;
27✔
1545
    if (mode == Doc::Operate)
27✔
1546
    {
1547
        m_progress->setStyleSheet(progressFadeStyle);
8✔
1548
        m_progress->setRange(0, m_progress->width());
8✔
1549
        enable = true;
8✔
1550
        // send the initial feedback for the current step slider
1551
        updateFeedback();
8✔
1552
    }
1553
    else
1554
    {
1555
        m_topStepLabel->setStyleSheet(cfLabelNoStyle);
19✔
1556
        m_topStepLabel->setText("");
19✔
1557
        m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
19✔
1558
        m_bottomStepLabel->setText("");
19✔
1559
        m_progress->setStyleSheet(progressDisabledStyle);
19✔
1560
        // reset any previously set background
1561
        QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
19✔
1562
        if (item != NULL)
19✔
1563
            item->setBackground(COL_NUM, m_defCol);
3✔
1564
    }
1565

1566
    enableWidgetUI(enable);
27✔
1567

1568
    /* Always start from the beginning */
1569
    m_tree->setCurrentItem(NULL);
27✔
1570

1571
    VCWidget::slotModeChanged(mode);
27✔
1572

1573
    emit sideFaderValueChanged();
27✔
1574
}
27✔
1575

1576
void VCCueList::editProperties()
×
1577
{
1578
    VCCueListProperties prop(this, m_doc);
×
1579
    if (prop.exec() == QDialog::Accepted)
×
1580
        m_doc->setModified();
×
1581
}
×
1582

1583
void VCCueList::playCueAtIndex(int idx)
4✔
1584
{
1585
    if (mode() != Doc::Operate)
4✔
1586
        return;
×
1587

1588
    m_primaryIndex = idx;
4✔
1589

1590
    Chaser *ch = chaser();
4✔
1591
    if (ch == NULL)
4✔
1592
        return;
×
1593

1594
    if (ch->isRunning())
4✔
1595
    {
1596
        ChaserAction action;
1597
        action.m_action = ChaserSetStepIndex;
3✔
1598
        action.m_stepIndex = m_primaryIndex;
3✔
1599
        action.m_masterIntensity = intensity();
3✔
1600
        action.m_stepIntensity = getPrimaryIntensity();
3✔
1601
        action.m_fadeMode = getFadeMode();
3✔
1602
        ch->setAction(action);
3✔
1603
    }
1604
    else
1605
    {
1606
        startChaser(m_primaryIndex);
1✔
1607
    }
1608

1609
    if (sideFaderMode() == Crossfade)
4✔
1610
        setFaderInfo(m_primaryIndex);
×
1611
}
1612

1613
FunctionParent VCCueList::functionParent() const
6✔
1614
{
1615
    return FunctionParent(FunctionParent::ManualVCWidget, id());
6✔
1616
}
1617

1618
/*****************************************************************************
1619
 * Load & Save
1620
 *****************************************************************************/
1621

1622
bool VCCueList::loadXML(QXmlStreamReader &root)
3✔
1623
{
1624
    QList <quint32> legacyStepList;
3✔
1625

1626
    if (root.name() != KXMLQLCVCCueList)
3✔
1627
    {
1628
        qWarning() << Q_FUNC_INFO << "CueList node not found";
1✔
1629
        return false;
1✔
1630
    }
1631

1632
    /* Widget commons */
1633
    loadXMLCommon(root);
2✔
1634

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

1733
    if (legacyStepList.isEmpty() == false)
2✔
1734
    {
1735
        /* Construct a new chaser from legacy step functions and use that chaser */
1736
        Chaser *chaser = new Chaser(m_doc);
1✔
1737
        chaser->setName(caption());
1✔
1738

1739
        // Legacy cue lists relied on individual functions' timings and a common hold time
1740
        chaser->setFadeInMode(Chaser::Default);
1✔
1741
        chaser->setFadeOutMode(Chaser::Default);
1✔
1742
        chaser->setDurationMode(Chaser::Common);
1✔
1743

1744
        foreach (quint32 id, legacyStepList)
7✔
1745
        {
1746
            Function *function = m_doc->function(id);
6✔
1747
            if (function == NULL)
6✔
1748
                continue;
2✔
1749

1750
            // Legacy cuelists relied on individual functions' fadein/out speed and
1751
            // infinite duration. So don't touch them at all.
1752
            ChaserStep step(id);
4✔
1753
            chaser->addStep(step);
4✔
1754
        }
5✔
1755

1756
        // Add the chaser to Doc and attach it to the cue list
1757
        m_doc->addFunction(chaser);
1✔
1758
        setChaser(chaser->id());
1✔
1759
    }
1760

1761
    return true;
2✔
1762
}
3✔
1763

1764
bool VCCueList::saveXML(QXmlStreamWriter *doc)
1✔
1765
{
1766
    Q_ASSERT(doc != NULL);
1✔
1767

1768
    /* VC CueList entry */
1769
    doc->writeStartElement(KXMLQLCVCCueList);
2✔
1770

1771
    saveXMLCommon(doc);
1✔
1772

1773
    /* Window state */
1774
    saveXMLWindowState(doc);
1✔
1775

1776
    /* Appearance */
1777
    saveXMLAppearance(doc);
1✔
1778

1779
    /* Chaser */
1780
    doc->writeTextElement(KXMLQLCVCCueListChaser, QString::number(chaserID()));
2✔
1781

1782
    /* Playback layout */
1783
    if (playbackLayout() != PlayPauseStop)
1✔
1784
        doc->writeTextElement(KXMLQLCVCCueListPlaybackLayout, QString::number(playbackLayout()));
×
1785

1786
    /* Next/Prev behavior */
1787
    doc->writeTextElement(KXMLQLCVCCueListNextPrevBehavior, QString::number(nextPrevBehavior()));
2✔
1788

1789
    /* Next cue */
1790
    doc->writeStartElement(KXMLQLCVCCueListNext);
2✔
1791
    if (m_nextKeySequence.toString().isEmpty() == false)
1✔
1792
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_nextKeySequence.toString());
2✔
1793
    saveXMLInput(doc, inputSource(nextInputSourceId));
1✔
1794
    doc->writeEndElement();
1✔
1795

1796
    /* Previous cue */
1797
    doc->writeStartElement(KXMLQLCVCCueListPrevious);
2✔
1798
    if (m_previousKeySequence.toString().isEmpty() == false)
1✔
1799
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_previousKeySequence.toString());
2✔
1800
    saveXMLInput(doc, inputSource(previousInputSourceId));
1✔
1801
    doc->writeEndElement();
1✔
1802

1803
    /* Cue list playback */
1804
    doc->writeStartElement(KXMLQLCVCCueListPlayback);
2✔
1805
    if (m_playbackKeySequence.toString().isEmpty() == false)
1✔
1806
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_playbackKeySequence.toString());
2✔
1807
    saveXMLInput(doc, inputSource(playbackInputSourceId));
1✔
1808
    doc->writeEndElement();
1✔
1809

1810
    /* Cue list stop */
1811
    doc->writeStartElement(KXMLQLCVCCueListStop);
2✔
1812
    if (m_stopKeySequence.toString().isEmpty() == false)
1✔
1813
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_stopKeySequence.toString());
2✔
1814
    saveXMLInput(doc, inputSource(stopInputSourceId));
1✔
1815
    doc->writeEndElement();
1✔
1816

1817
    /* Crossfade cue list */
1818
    if (sideFaderMode() != None)
1✔
1819
        doc->writeTextElement(KXMLQLCVCCueListSlidersMode, faderModeToString(sideFaderMode()));
2✔
1820

1821
    QSharedPointer<QLCInputSource> cf1Src = inputSource(sideFaderInputSourceId);
1✔
1822
    if (!cf1Src.isNull() && cf1Src->isValid())
1✔
1823
    {
1824
        doc->writeStartElement(KXMLQLCVCCueListCrossfadeLeft);
×
1825
        saveXMLInput(doc, cf1Src);
×
1826
        doc->writeEndElement();
×
1827
    }
1828

1829
    /* End the <CueList> tag */
1830
    doc->writeEndElement();
1✔
1831

1832
    return true;
1✔
1833
}
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