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

mcallegari / qlcplus / 8961243534

05 May 2024 09:23PM UTC coverage: 32.068% (+4.0%) from 28.094%
8961243534

push

github

mcallegari
Merge branch 'master' into qmltoqt6

902 of 2557 new or added lines in 140 files covered. (35.28%)

166 existing lines in 76 files now uncovered.

15395 of 48008 relevant lines covered (32.07%)

22949.67 hits per line

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

60.83
/ui/src/virtualconsole/vccuelist.cpp
1
/*
2
  Q Light Controller Plus
3
  vccuelist.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

21
#include <QStyledItemDelegate>
22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QTreeWidgetItem>
25
#include <QFontMetrics>
26
#include <QProgressBar>
27
#include <QTreeWidget>
28
#include <QHeaderView>
29
#include <QGridLayout>
30
#include <QSettings>
31
#include <QCheckBox>
32
#include <QString>
33
#include <QLabel>
34
#include <QDebug>
35
#include <QTimer>
36

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

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

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

62
#define PROGRESS_INTERVAL 200
63
#define UPDATE_TIMEOUT 100
64

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

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

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

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

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

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

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

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

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

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

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

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

146
    slotShowCrossfadePanel(false);
15✔
147

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

307
    return cuelist;
1✔
308
}
309

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

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

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

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

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

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

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

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

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

368
    updateStepList();
14✔
369

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

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

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

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

397
    m_tree->clear();
15✔
398

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

569
    stopChaser();
×
570
}
571

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

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

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

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

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

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

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

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

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

660
    emit playbackButtonClicked();
2✔
661
}
662

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

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

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

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

NEW
705
    emit stopButtonClicked();
×
706
}
707

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

926
    emit stepChanged(-1);
14✔
927

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1047
    return Chaser::Blended;
×
1048
}
1049

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

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

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

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

1087
    m_playbackLayout = layout;
×
1088
}
1089

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

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

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

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

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

1122
    return None;
×
1123
}
1124

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

1132
    return "None";
×
1133
}
1134

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

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

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

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

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

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

1162
    emit sideFaderValueChanged();
19✔
1163
}
1164

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

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

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

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

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

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

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

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

NEW
1206
void VCCueList::slotSideFaderButtonChecked(bool enable)
×
1207
{
NEW
1208
    m_crossfadeButton->setChecked(enable);
×
NEW
1209
}
×
1210

NEW
1211
bool VCCueList::isSideFaderVisible()
×
1212
{
NEW
1213
    return m_sideFader->isVisible();
×
1214
}
1215

NEW
1216
bool VCCueList::sideFaderButtonChecked()
×
1217
{
NEW
1218
    return m_crossfadeButton->isChecked();
×
1219
}
1220

NEW
1221
void VCCueList::slotSetSideFaderValue(int value)
×
1222
{
NEW
1223
    m_sideFader->setValue(value);
×
UNCOV
1224
}
×
1225

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

NEW
1233
        emit sideFaderValueChanged();
×
1234

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

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

UNCOV
1251
        if (newStep == ch->currentStepIndex())
×
1252
            return;
×
1253

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

NEW
1267
        emit sideFaderValueChanged();
×
1268

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

1280
    updateFeedback();
×
1281
}
1282

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

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

1291
    ChaserAction action;
1292
    action.m_action = ChaserStopStep;
×
1293

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

1307
/*****************************************************************************
1308
 * Key Sequences
1309
 *****************************************************************************/
1310

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

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

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

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

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

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

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

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

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

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

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

1374
    Chaser *ch = chaser();
25✔
1375
    if (ch == NULL)
25✔
1376
        return;
3✔
1377

1378
    sendFeedback(ch->isRunning() ? UCHAR_MAX : 0, playbackInputSourceId);
22✔
1379
}
1380

1381
/*****************************************************************************
1382
 * External Input
1383
 *****************************************************************************/
1384

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

1391
    quint32 pagedCh = (page() << 16) | channel;
12✔
1392

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

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

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

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

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

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

1481
/*****************************************************************************
1482
 * VCWidget-inherited methods
1483
 *****************************************************************************/
1484

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

1501
    VCWidget::adjustIntensity(val);
×
1502
}
×
1503

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

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

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

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

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

1551
    enableWidgetUI(enable);
23✔
1552

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

1556
    VCWidget::slotModeChanged(mode);
23✔
1557

1558
    emit sideFaderValueChanged();
23✔
1559
}
23✔
1560

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

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

1573
    m_primaryIndex = idx;
4✔
1574

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

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

1594
    if (sideFaderMode() == Crossfade)
4✔
1595
        setFaderInfo(m_primaryIndex);
×
1596
}
1597

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

1603
/*****************************************************************************
1604
 * Load & Save
1605
 *****************************************************************************/
1606

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

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

1617
    /* Widget commons */
1618
    loadXMLCommon(root);
2✔
1619

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

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

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

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

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

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

1746
    return true;
2✔
1747
}
1748

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

1753
    /* VC CueList entry */
1754
    doc->writeStartElement(KXMLQLCVCCueList);
1✔
1755

1756
    saveXMLCommon(doc);
1✔
1757

1758
    /* Window state */
1759
    saveXMLWindowState(doc);
1✔
1760

1761
    /* Appearance */
1762
    saveXMLAppearance(doc);
1✔
1763

1764
    /* Chaser */
1765
    doc->writeTextElement(KXMLQLCVCCueListChaser, QString::number(chaserID()));
1✔
1766

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

1771
    /* Next/Prev behavior */
1772
    doc->writeTextElement(KXMLQLCVCCueListNextPrevBehavior, QString::number(nextPrevBehavior()));
1✔
1773

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

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

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

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

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

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

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

1817
    return true;
2✔
1818
}
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