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

mcallegari / qlcplus / 7339023038

27 Dec 2023 02:03PM UTC coverage: 32.066% (-0.001%) from 32.067%
7339023038

push

github

web-flow
Cuelist slider fix (#1396)

* Fix off-by-1 issue with slider<->step# calculations

When the Step # changed, or the SliderValue changed, in Steps mode, the calculation to convert step# to value or vice versa had some off-by-one issues. The main visible symptom was that the slider position didn't always update when clicking the PreviousCue button (in a 6-step chaser, it would update the slider position every-other-click). Also, if moving the slider position using up/down arrows, the step # didn't change at the exact same slider positions as were jumped to using the Next-Cue button.

In v5 this is perhaps not necessary, because the slider position doesn't update if the Current Step changes; but if code is ever added to set the slider position on current step changing the same fix for the same reason is applicable here too.

0 of 11 new or added lines in 1 file covered. (0.0%)

2 existing lines in 1 file now uncovered.

15169 of 47306 relevant lines covered (32.07%)

23737.32 hits per line

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

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

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

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

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

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

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

62
#define PROGRESS_INTERVAL 200
63
#define UPDATE_TIMEOUT 100
64

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

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

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

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

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

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

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

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

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

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

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

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

146
    slotShowCrossfadePanel(false);
15✔
147

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

307
    return cuelist;
1✔
308
}
309

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

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

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

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

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

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

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

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

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

368
    updateStepList();
14✔
369

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

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

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

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

397
    m_tree->clear();
15✔
398

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

569
    stopChaser();
×
570
}
571

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

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

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

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

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

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

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

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

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

660
    emit playbackButtonClicked();
2✔
661
}
662

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

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

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

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

705
    emit stopButtonClicked();
×
706
}
707

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

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

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

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

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

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

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

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

818
        float stepVal;
819
        int stepsCount = m_tree->topLevelItemCount();
×
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
}
884

885
void VCCueList::slotFunctionRunning(quint32 fid)
4✔
886
{
887
    if (fid != m_chaserID)
4✔
888
        return;
×
889

890
    if (playbackLayout() == PlayPauseStop)
4✔
891
        m_playbackButton->setIcon(QIcon(":/player_pause.png"));
4✔
892
    else if (playbackLayout() == PlayStopPause)
×
893
        m_playbackButton->setIcon(QIcon(":/player_stop.png"));
×
894
    m_timer->start(PROGRESS_INTERVAL);
4✔
895
    emit playbackStatusChanged();
4✔
896
    updateFeedback();
4✔
897
}
898

899
void VCCueList::slotFunctionStopped(quint32 fid)
14✔
900
{
901
    if (fid != m_chaserID)
14✔
902
        return;
×
903

904
    m_playbackButton->setIcon(QIcon(":/player_play.png"));
14✔
905
    m_topStepLabel->setText("");
14✔
906
    m_topStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
907
    m_bottomStepLabel->setText("");
14✔
908
    m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
14✔
909
    // reset any previously set background
910
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
14✔
911
    if (item != NULL)
14✔
912
        item->setBackground(COL_NUM, m_defCol);
11✔
913

914
    emit stepChanged(-1);
14✔
915

916
    m_progress->setFormat("");
14✔
917
    m_progress->setValue(0);    
14✔
918

919
    emit progressStateChanged();
14✔
920
    emit sideFaderValueChanged();
14✔
921
    emit playbackStatusChanged();
14✔
922

923
    qDebug() << Q_FUNC_INFO << "Cue stopped";
14✔
924
    updateFeedback();
14✔
925
}
926

927
void VCCueList::slotProgressTimeout()
×
928
{
929
    Chaser *ch = chaser();
×
930
    if (ch == NULL || !ch->isRunning())
×
931
        return;
×
932

933
    ChaserRunnerStep step(ch->currentRunningStep());
×
934
    if (step.m_function != NULL)
×
935
    {
936
        int status = m_progress->property("status").toInt();
×
937
        int newstatus;
938
        if (step.m_fadeIn == Function::defaultSpeed())
×
939
            newstatus = 1;
×
940
        else if (step.m_elapsed > (quint32)step.m_fadeIn)
×
941
            newstatus = 1;
×
942
        else
943
            newstatus = 0;
×
944

945
        if (newstatus != status)
×
946
        {
947
            if (newstatus == 0)
×
948
                m_progress->setStyleSheet(progressFadeStyle);
×
949
            else
950
                m_progress->setStyleSheet(progressHoldStyle);
×
951
            m_progress->setProperty("status", newstatus);
×
952
        }
953
        if (step.m_duration == Function::infiniteSpeed())
×
954
        {
955
            if (newstatus == 0 && step.m_fadeIn != Function::defaultSpeed())
×
956
            {
957
                double progress = ((double)step.m_elapsed / (double)step.m_fadeIn) * (double)m_progress->width();
×
958
                m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_fadeIn - step.m_elapsed)));
×
959
                m_progress->setValue(progress);
×
960

961
                emit progressStateChanged();
×
962
            }
963
            else
964
            {
965
                m_progress->setValue(m_progress->maximum());
×
966
                m_progress->setFormat("");
×
967

968
                emit progressStateChanged();
×
969
            }
970
            return;
×
971
        }
972
        else
973
        {
974
            double progress = ((double)step.m_elapsed / (double)step.m_duration) * (double)m_progress->width();
×
975
            m_progress->setFormat(QString("-%1").arg(Function::speedToString(step.m_duration - step.m_elapsed)));
×
976
            m_progress->setValue(progress);
×
977

978
            emit progressStateChanged();
×
979
        }
980
    }
981
    else
982
    {
983
        m_progress->setValue(0);
×
984
    }
985
}
986

987
QString VCCueList::progressText()
×
988
{
989
    return m_progress->text();
×
990
}
991

992
double VCCueList::progressPercent()
×
993
{
994
    return ((double)m_progress->value() * 100) / (double)m_progress->width();
×
995
}
996

997
void VCCueList::startChaser(int startIndex)
4✔
998
{
999
    Chaser *ch = chaser();
4✔
1000
    if (ch == NULL)
4✔
1001
        return;
×
1002

1003
    adjustFunctionIntensity(ch, intensity());
4✔
1004

1005
    ChaserAction action;
1006
    action.m_action = ChaserSetStepIndex;
4✔
1007
    action.m_stepIndex = startIndex;
4✔
1008
    action.m_masterIntensity = intensity();
4✔
1009
    action.m_stepIntensity = getPrimaryIntensity();
4✔
1010
    action.m_fadeMode = getFadeMode();
4✔
1011
    ch->setAction(action);
4✔
1012

1013
    ch->start(m_doc->masterTimer(), functionParent());
4✔
1014
    emit functionStarting(m_chaserID);
4✔
1015
}
1016

1017
void VCCueList::stopChaser()
×
1018
{
1019
    Chaser *ch = chaser();
×
1020
    if (ch == NULL)
×
1021
        return;
×
1022

1023
    ch->stop(functionParent());
×
1024
    resetIntensityOverrideAttribute();
×
1025
}
1026

1027
int VCCueList::getFadeMode()
20✔
1028
{
1029
    if (sideFaderMode() != Crossfade)
20✔
1030
        return Chaser::FromFunction;
20✔
1031

1032
    if (m_sideFader->value() != 0 && m_sideFader->value() != 100)
×
1033
        return Chaser::BlendedCrossfade;
×
1034

1035
    return Chaser::Blended;
×
1036
}
1037

1038
void VCCueList::setNextPrevBehavior(NextPrevBehavior nextPrev)
×
1039
{
1040
    Q_ASSERT(nextPrev == DefaultRunFirst
×
1041
            || nextPrev == RunNext
1042
            || nextPrev == Select
1043
            || nextPrev == Nothing);
1044
    m_nextPrevBehavior = nextPrev;
×
1045
}
×
1046

1047
VCCueList::NextPrevBehavior VCCueList::nextPrevBehavior() const
1✔
1048
{
1049
    return m_nextPrevBehavior;
1✔
1050
}
1051

1052
void VCCueList::setPlaybackLayout(VCCueList::PlaybackLayout layout)
×
1053
{
1054
    if (layout == m_playbackLayout)
×
1055
        return;
×
1056

1057
    if (layout == PlayStopPause)
×
1058
    {
1059
        m_stopButton->setIcon(QIcon(":/player_pause.png"));
×
1060
        m_playbackButton->setToolTip(tr("Play/Stop Cue list"));
×
1061
        m_stopButton->setToolTip(tr("Pause Cue list"));
×
1062
    }
1063
    else if (layout == PlayPauseStop)
×
1064
    {
1065
        m_stopButton->setIcon(QIcon(":/player_stop.png"));
×
1066
        m_playbackButton->setToolTip(tr("Play/Pause Cue list"));
×
1067
        m_stopButton->setToolTip(tr("Stop Cue list"));
×
1068
    }
1069
    else
1070
    {
1071
        qWarning() << "Playback layout" << layout << "doesn't exist!";
×
1072
        layout = PlayPauseStop;
×
1073
    }
1074

1075
    m_playbackLayout = layout;
×
1076
}
1077

1078
VCCueList::PlaybackLayout VCCueList::playbackLayout() const
7✔
1079
{
1080
    return m_playbackLayout;
7✔
1081
}
1082

1083
VCCueList::FaderMode VCCueList::sideFaderMode() const
67✔
1084
{
1085
    return m_slidersMode;
67✔
1086
}
1087

1088
void VCCueList::setSideFaderMode(VCCueList::FaderMode mode)
3✔
1089
{
1090
    m_slidersMode = mode;
3✔
1091

1092
    bool show = (mode == None) ? false : true;
3✔
1093
    m_crossfadeButton->setVisible(show);
3✔
1094
    m_topPercentageLabel->setVisible(show);
3✔
1095
    m_topStepLabel->setVisible(mode == Steps ? false : show);
3✔
1096
    m_sideFader->setVisible(show);
3✔
1097
    m_bottomPercentageLabel->setVisible(mode == Steps ? false : show);
3✔
1098
    m_bottomStepLabel->setVisible(show);
3✔
1099
    m_sideFader->setMaximum(mode == Steps ? 255 : 100);
3✔
1100
    m_sideFader->setValue(mode == Steps ? 255 : 100);
3✔
1101
}
3✔
1102

1103
VCCueList::FaderMode VCCueList::stringToFaderMode(QString modeStr)
×
1104
{
1105
    if (modeStr == "Crossfade")
×
1106
        return Crossfade;
×
1107
    else if (modeStr == "Steps")
×
1108
        return Steps;
×
1109

1110
    return None;
×
1111
}
1112

1113
QString VCCueList::faderModeToString(VCCueList::FaderMode mode)
1✔
1114
{
1115
    if (mode == Crossfade)
1✔
1116
        return "Crossfade";
1✔
1117
    else if (mode == Steps)
×
1118
        return "Steps";
×
1119

1120
    return "None";
×
1121
}
1122

1123
/*****************************************************************************
1124
 * Crossfade
1125
 *****************************************************************************/
1126
void VCCueList::setFaderInfo(int index)
19✔
1127
{
1128
    Chaser *ch = chaser();
19✔
1129
    if (ch == NULL || !ch->isRunning())
19✔
1130
        return;
×
1131

1132
    int tmpIndex = ch->computeNextStep(index);
19✔
1133

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

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

1140
    // reset any previously set background
1141
    QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
19✔
1142
    if (item != NULL)
19✔
1143
        item->setBackground(COL_NUM, m_defCol);
19✔
1144

1145
    item = m_tree->topLevelItem(tmpIndex);
19✔
1146
    if (item != NULL)
19✔
1147
        item->setBackground(COL_NUM, QColor("#FF8000"));
19✔
1148
    m_secondaryIndex = tmpIndex;
19✔
1149

1150
    emit sideFaderValueChanged();
19✔
1151
}
1152

1153
void VCCueList::slotShowCrossfadePanel(bool enable)
15✔
1154
{
1155
    m_topPercentageLabel->setVisible(enable);
15✔
1156
    m_topStepLabel->setVisible(enable);
15✔
1157
    m_sideFader->setVisible(enable);
15✔
1158
    m_bottomStepLabel->setVisible(enable);
15✔
1159
    m_bottomPercentageLabel->setVisible(enable);
15✔
1160

1161
    emit sideFaderButtonToggled();
15✔
1162
}
15✔
1163

1164
QString VCCueList::topPercentageValue()
×
1165
{
1166
    return m_topPercentageLabel->text();
×
1167
}
1168

1169
QString VCCueList::bottomPercentageValue()
×
1170
{
1171
    return m_bottomPercentageLabel->text();
×
1172
}
1173

1174
QString VCCueList::topStepValue()
×
1175
{
1176
    return m_topStepLabel->text();
×
1177
}
1178

1179
QString VCCueList::bottomStepValue()
×
1180
{
1181
    return m_bottomStepLabel->text();
×
1182
}
1183

1184
int VCCueList::sideFaderValue()
×
1185
{
1186
    return m_sideFader->value();
×
1187
}
1188

1189
bool VCCueList::primaryTop()
×
1190
{
1191
    return m_primaryTop;
×
1192
}
1193

1194
void VCCueList::slotSideFaderButtonChecked(bool enable)
×
1195
{
1196
    m_crossfadeButton->setChecked(enable);
×
1197
}
×
1198

1199
bool VCCueList::isSideFaderVisible()
×
1200
{
1201
    return m_sideFader->isVisible();
×
1202
}
1203

1204
bool VCCueList::sideFaderButtonChecked()
×
1205
{
1206
    return m_crossfadeButton->isChecked();
×
1207
}
1208

1209
void VCCueList::slotSetSideFaderValue(int value)
×
1210
{
1211
    m_sideFader->setValue(value);
×
1212
}
×
1213

1214
void VCCueList::slotSideFaderValueChanged(int value)
×
1215
{
1216
    if (sideFaderMode() == Steps)
×
1217
    {
1218
        value = 255 - value;
×
1219
        m_topPercentageLabel->setText(QString("%1").arg(value));
×
1220

1221
        emit sideFaderValueChanged();
×
1222

1223
        Chaser *ch = chaser();
×
1224
        if (ch == NULL || ch->stopped())
×
1225
            return;
×
1226

1227
        int newStep = value; // by default we assume the Chaser has more than 256 steps
×
1228
        if (ch->stepsCount() < 256)
×
1229
        {
NEW
1230
            float stepSize = 256.0 / (float)ch->stepsCount();  //divide up the full 0..255 range
×
NEW
1231
            stepSize = qFloor((stepSize * 100000.0) + 0.5) / 100000.0; //round to 5 decimals to fix corner cases
×
NEW
1232
            if (value >= 256.0 - stepSize)
×
UNCOV
1233
                newStep = ch->stepsCount() - 1;
×
1234
            else
1235
                newStep = qFloor((float)value / stepSize);
×
1236
            //qDebug() << "value:" << value << " new step:" << newStep << " stepSize:" << stepSize;
1237
        }
1238

UNCOV
1239
        if (newStep == ch->currentStepIndex())
×
1240
            return;
×
1241

1242
        ChaserAction action;
1243
        action.m_action = ChaserSetStepIndex;
×
1244
        action.m_stepIndex = newStep;
×
1245
        action.m_masterIntensity = intensity();
×
1246
        action.m_stepIntensity = getPrimaryIntensity();
×
1247
        action.m_fadeMode = getFadeMode();
×
1248
        ch->setAction(action);
×
1249
    }
1250
    else
1251
    {
1252
        m_topPercentageLabel->setText(QString("%1%").arg(value));
×
1253
        m_bottomPercentageLabel->setText(QString("%1%").arg(100 - value));
×
1254

1255
        emit sideFaderValueChanged();
×
1256

1257
        Chaser *ch = chaser();
×
1258
        if (!(ch == NULL || ch->stopped()))
×
1259
        {
1260
            ch->adjustStepIntensity(qreal(value) / 100.0, m_primaryTop ? m_primaryIndex : m_secondaryIndex,
×
1261
                                    Chaser::FadeControlMode(getFadeMode()));
×
1262
            ch->adjustStepIntensity(qreal(100 - value) / 100.0, m_primaryTop ? m_secondaryIndex : m_primaryIndex,
×
1263
                                    Chaser::FadeControlMode(getFadeMode()));
×
1264
            stopStepIfNeeded(ch);
×
1265
        }
1266
    }
1267

1268
    updateFeedback();
×
1269
}
1270

1271
void VCCueList::stopStepIfNeeded(Chaser *ch)
×
1272
{
1273
    if (ch->runningStepsNumber() != 2)
×
1274
        return;
×
1275

1276
    int primaryValue = m_primaryTop ? m_sideFader->value() : 100 - m_sideFader->value();
×
1277
    int secondaryValue = m_primaryTop ? 100 - m_sideFader->value() : m_sideFader->value();
×
1278

1279
    ChaserAction action;
1280
    action.m_action = ChaserStopStep;
×
1281

1282
    if (primaryValue == 0)
×
1283
    {
1284
        m_primaryTop = !m_primaryTop;
×
1285
        action.m_stepIndex = m_primaryIndex;
×
1286
        ch->setAction(action);
×
1287
    }
1288
    else if (secondaryValue == 0)
×
1289
    {
1290
        action.m_stepIndex = m_secondaryIndex;
×
1291
        ch->setAction(action);
×
1292
    }
1293
}
1294

1295
/*****************************************************************************
1296
 * Key Sequences
1297
 *****************************************************************************/
1298

1299
void VCCueList::setNextKeySequence(const QKeySequence& keySequence)
6✔
1300
{
1301
    m_nextKeySequence = QKeySequence(keySequence);
6✔
1302
}
6✔
1303

1304
QKeySequence VCCueList::nextKeySequence() const
8✔
1305
{
1306
    return m_nextKeySequence;
8✔
1307
}
1308

1309
void VCCueList::setPreviousKeySequence(const QKeySequence& keySequence)
6✔
1310
{
1311
    m_previousKeySequence = QKeySequence(keySequence);
6✔
1312
}
6✔
1313

1314
QKeySequence VCCueList::previousKeySequence() const
8✔
1315
{
1316
    return m_previousKeySequence;
8✔
1317
}
1318

1319
void VCCueList::setPlaybackKeySequence(const QKeySequence& keySequence)
6✔
1320
{
1321
    m_playbackKeySequence = QKeySequence(keySequence);
6✔
1322
}
6✔
1323

1324
QKeySequence VCCueList::playbackKeySequence() const
8✔
1325
{
1326
    return m_playbackKeySequence;
8✔
1327
}
1328

1329
void VCCueList::setStopKeySequence(const QKeySequence &keySequence)
3✔
1330
{
1331
    m_stopKeySequence = QKeySequence(keySequence);
3✔
1332
}
3✔
1333

1334
QKeySequence VCCueList::stopKeySequence() const
3✔
1335
{
1336
    return m_stopKeySequence;
3✔
1337
}
1338

1339
void VCCueList::slotKeyPressed(const QKeySequence& keySequence)
7✔
1340
{
1341
    if (acceptsInput() == false)
7✔
1342
        return;
×
1343

1344
    if (m_nextKeySequence == keySequence)
7✔
1345
        slotNextCue();
3✔
1346
    else if (m_previousKeySequence == keySequence)
4✔
1347
        slotPreviousCue();
2✔
1348
    else if (m_playbackKeySequence == keySequence)
2✔
1349
        slotPlayback();
1✔
1350
    else if (m_stopKeySequence == keySequence)
1✔
1351
        slotStop();
×
1352
}
1353

1354
void VCCueList::updateFeedback()
25✔
1355
{
1356
    int fbv = int(SCALE(float(m_sideFader->value()), 
25✔
1357
                        float(m_sideFader->minimum()),
1358
                        float(m_sideFader->maximum()), 
1359
                        float(0), float(UCHAR_MAX)));
25✔
1360
    sendFeedback(fbv, sideFaderInputSourceId);
25✔
1361

1362
    Chaser *ch = chaser();
25✔
1363
    if (ch == NULL)
25✔
1364
        return;
3✔
1365

1366
    sendFeedback(ch->isRunning() ? UCHAR_MAX : 0, playbackInputSourceId);
22✔
1367
}
1368

1369
/*****************************************************************************
1370
 * External Input
1371
 *****************************************************************************/
1372

1373
void VCCueList::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
12✔
1374
{
1375
    /* Don't let input data through in design mode or if disabled */
1376
    if (acceptsInput() == false)
12✔
1377
        return;
×
1378

1379
    quint32 pagedCh = (page() << 16) | channel;
12✔
1380

1381
    if (checkInputSource(universe, pagedCh, value, sender(), nextInputSourceId))
12✔
1382
    {
1383
        // Use hysteresis for values, in case the cue list is being controlled
1384
        // by a slider. The value has to go to zero before the next non-zero
1385
        // value is accepted as input. And the non-zero values have to visit
1386
        // above $HYSTERESIS before a zero is accepted again.
1387
        if (m_nextLatestValue == 0 && value > 0)
3✔
1388
        {
1389
            slotNextCue();
2✔
1390
            m_nextLatestValue = value;
2✔
1391
        }
1392
        else if (m_nextLatestValue > HYSTERESIS && value == 0)
1✔
1393
        {
1394
            m_nextLatestValue = 0;
1✔
1395
        }
1396

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

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

1435
        if (value > HYSTERESIS)
2✔
1436
            m_playbackLatestValue = value;
1✔
1437
    }
1438
    else if (checkInputSource(universe, pagedCh, value, sender(), stopInputSourceId))
4✔
1439
    {
1440
        // Use hysteresis for values, in case the cue list is being controlled
1441
        // by a slider. The value has to go to zero before the next non-zero
1442
        // value is accepted as input. And the non-zero values have to visit
1443
        // above $HYSTERESIS before a zero is accepted again.
1444
        if (m_stopLatestValue == 0 && value > 0)
×
1445
        {
1446
            slotStop();
×
1447
            m_stopLatestValue = value;
×
1448
        }
1449
        else if (m_stopLatestValue > HYSTERESIS && value == 0)
×
1450
        {
1451
            m_stopLatestValue = 0;
×
1452
        }
1453

1454
        if (value > HYSTERESIS)
×
1455
            m_stopLatestValue = value;
×
1456
    }
1457
    else if (checkInputSource(universe, pagedCh, value, sender(), sideFaderInputSourceId))
4✔
1458
    {
1459
        if (sideFaderMode() == None)
×
1460
            return;
×
1461

1462
        float val = SCALE((float) value, (float) 0, (float) UCHAR_MAX,
×
1463
                          (float) m_sideFader->minimum(),
1464
                          (float) m_sideFader->maximum());
1465
        m_sideFader->setValue(val);
×
1466
    }
1467
}
1468

1469
/*****************************************************************************
1470
 * VCWidget-inherited methods
1471
 *****************************************************************************/
1472

1473
void VCCueList::adjustIntensity(qreal val)
×
1474
{
1475
    Chaser *ch = chaser();
×
1476
    if (ch != NULL)
×
1477
    {
1478
        adjustFunctionIntensity(ch, val);
×
1479
/*
1480
        // Refresh intensity of current steps
1481
        if (!ch->stopped() && sideFaderMode() == Crossfade && m_sideFader->value() != 100)
1482
        {
1483
                ch->adjustStepIntensity((qreal)m_sideFader->value() / 100, m_primaryTop ? m_primaryIndex : m_secondaryIndex);
1484
                ch->adjustStepIntensity((qreal)(100 - m_sideFader->value()) / 100, m_primaryTop ? m_secondaryIndex : m_primaryIndex);
1485
        }
1486
*/
1487
    }
1488

1489
    VCWidget::adjustIntensity(val);
×
1490
}
×
1491

1492
void VCCueList::setCaption(const QString& text)
20✔
1493
{
1494
    VCWidget::setCaption(text);
20✔
1495

1496
    QStringList list;
40✔
1497
    list << "#" << text << tr("Fade In") << tr("Fade Out") << tr("Duration") << tr("Notes");
20✔
1498
    m_tree->setHeaderLabels(list);
20✔
1499
}
20✔
1500

1501
void VCCueList::setFont(const QFont& font)
1✔
1502
{
1503
    VCWidget::setFont(font);
1✔
1504

1505
    QFontMetrics m_fm = QFontMetrics(font);
2✔
1506
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
1507
    int w = m_fm.width("100%");
1508
#else
1509
    int w = m_fm.horizontalAdvance("100%");
1✔
1510
#endif
1511
    m_topPercentageLabel->setFixedWidth(w);
1✔
1512
    m_bottomPercentageLabel->setFixedWidth(w);
1✔
1513
}
1✔
1514

1515
void VCCueList::slotModeChanged(Doc::Mode mode)
23✔
1516
{
1517
    bool enable = false;
23✔
1518
    if (mode == Doc::Operate)
23✔
1519
    {
1520
        m_progress->setStyleSheet(progressFadeStyle);
6✔
1521
        m_progress->setRange(0, m_progress->width());
6✔
1522
        enable = true;
6✔
1523
        // send the initial feedback for the current step slider
1524
        updateFeedback();
6✔
1525
    }
1526
    else
1527
    {
1528
        m_topStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1529
        m_topStepLabel->setText("");
17✔
1530
        m_bottomStepLabel->setStyleSheet(cfLabelNoStyle);
17✔
1531
        m_bottomStepLabel->setText("");
17✔
1532
        m_progress->setStyleSheet(progressDisabledStyle);
17✔
1533
        // reset any previously set background
1534
        QTreeWidgetItem *item = m_tree->topLevelItem(m_secondaryIndex);
17✔
1535
        if (item != NULL)
17✔
1536
            item->setBackground(COL_NUM, m_defCol);
2✔
1537
    }
1538

1539
    enableWidgetUI(enable);
23✔
1540

1541
    /* Always start from the beginning */
1542
    m_tree->setCurrentItem(NULL);
23✔
1543

1544
    VCWidget::slotModeChanged(mode);
23✔
1545

1546
    emit sideFaderValueChanged();
23✔
1547
}
23✔
1548

1549
void VCCueList::editProperties()
×
1550
{
1551
    VCCueListProperties prop(this, m_doc);
×
1552
    if (prop.exec() == QDialog::Accepted)
×
1553
        m_doc->setModified();
×
1554
}
×
1555

1556
void VCCueList::playCueAtIndex(int idx)
4✔
1557
{
1558
    if (mode() != Doc::Operate)
4✔
1559
        return;
×
1560

1561
    m_primaryIndex = idx;
4✔
1562

1563
    Chaser *ch = chaser();
4✔
1564
    if (ch == NULL)
4✔
1565
        return;
×
1566

1567
    if (ch->isRunning())
4✔
1568
    {
1569
        ChaserAction action;
1570
        action.m_action = ChaserSetStepIndex;
3✔
1571
        action.m_stepIndex = m_primaryIndex;
3✔
1572
        action.m_masterIntensity = intensity();
3✔
1573
        action.m_stepIntensity = getPrimaryIntensity();
3✔
1574
        action.m_fadeMode = getFadeMode();
3✔
1575
        ch->setAction(action);
3✔
1576
    }
1577
    else
1578
    {
1579
        startChaser(m_primaryIndex);
1✔
1580
    }
1581

1582
    if (sideFaderMode() == Crossfade)
4✔
1583
        setFaderInfo(m_primaryIndex);
×
1584
}
1585

1586
FunctionParent VCCueList::functionParent() const
4✔
1587
{
1588
    return FunctionParent(FunctionParent::ManualVCWidget, id());
4✔
1589
}
1590

1591
/*****************************************************************************
1592
 * Load & Save
1593
 *****************************************************************************/
1594

1595
bool VCCueList::loadXML(QXmlStreamReader &root)
3✔
1596
{
1597
    QList <quint32> legacyStepList;
6✔
1598

1599
    if (root.name() != KXMLQLCVCCueList)
3✔
1600
    {
1601
        qWarning() << Q_FUNC_INFO << "CueList node not found";
1✔
1602
        return false;
1✔
1603
    }
1604

1605
    /* Widget commons */
1606
    loadXMLCommon(root);
2✔
1607

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

1706
    if (legacyStepList.isEmpty() == false)
2✔
1707
    {
1708
        /* Construct a new chaser from legacy step functions and use that chaser */
1709
        Chaser *chaser = new Chaser(m_doc);
1✔
1710
        chaser->setName(caption());
1✔
1711

1712
        // Legacy cue lists relied on individual functions' timings and a common hold time
1713
        chaser->setFadeInMode(Chaser::Default);
1✔
1714
        chaser->setFadeOutMode(Chaser::Default);
1✔
1715
        chaser->setDurationMode(Chaser::Common);
1✔
1716

1717
        foreach (quint32 id, legacyStepList)
13✔
1718
        {
1719
            Function *function = m_doc->function(id);
6✔
1720
            if (function == NULL)
6✔
1721
                continue;
2✔
1722

1723
            // Legacy cuelists relied on individual functions' fadein/out speed and
1724
            // infinite duration. So don't touch them at all.
1725
            ChaserStep step(id);
8✔
1726
            chaser->addStep(step);
4✔
1727
        }
1728

1729
        // Add the chaser to Doc and attach it to the cue list
1730
        m_doc->addFunction(chaser);
1✔
1731
        setChaser(chaser->id());
1✔
1732
    }
1733

1734
    return true;
2✔
1735
}
1736

1737
bool VCCueList::saveXML(QXmlStreamWriter *doc)
1✔
1738
{
1739
    Q_ASSERT(doc != NULL);
1✔
1740

1741
    /* VC CueList entry */
1742
    doc->writeStartElement(KXMLQLCVCCueList);
1✔
1743

1744
    saveXMLCommon(doc);
1✔
1745

1746
    /* Window state */
1747
    saveXMLWindowState(doc);
1✔
1748

1749
    /* Appearance */
1750
    saveXMLAppearance(doc);
1✔
1751

1752
    /* Chaser */
1753
    doc->writeTextElement(KXMLQLCVCCueListChaser, QString::number(chaserID()));
1✔
1754

1755
    /* Playback layout */
1756
    if (playbackLayout() != PlayPauseStop)
1✔
1757
        doc->writeTextElement(KXMLQLCVCCueListPlaybackLayout, QString::number(playbackLayout()));
×
1758

1759
    /* Next/Prev behavior */
1760
    doc->writeTextElement(KXMLQLCVCCueListNextPrevBehavior, QString::number(nextPrevBehavior()));
1✔
1761

1762
    /* Next cue */
1763
    doc->writeStartElement(KXMLQLCVCCueListNext);
1✔
1764
    if (m_nextKeySequence.toString().isEmpty() == false)
1✔
1765
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_nextKeySequence.toString());
1✔
1766
    saveXMLInput(doc, inputSource(nextInputSourceId));
1✔
1767
    doc->writeEndElement();
1✔
1768

1769
    /* Previous cue */
1770
    doc->writeStartElement(KXMLQLCVCCueListPrevious);
1✔
1771
    if (m_previousKeySequence.toString().isEmpty() == false)
1✔
1772
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_previousKeySequence.toString());
1✔
1773
    saveXMLInput(doc, inputSource(previousInputSourceId));
1✔
1774
    doc->writeEndElement();
1✔
1775

1776
    /* Cue list playback */
1777
    doc->writeStartElement(KXMLQLCVCCueListPlayback);
1✔
1778
    if (m_playbackKeySequence.toString().isEmpty() == false)
1✔
1779
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_playbackKeySequence.toString());
1✔
1780
    saveXMLInput(doc, inputSource(playbackInputSourceId));
1✔
1781
    doc->writeEndElement();
1✔
1782

1783
    /* Cue list stop */
1784
    doc->writeStartElement(KXMLQLCVCCueListStop);
1✔
1785
    if (m_stopKeySequence.toString().isEmpty() == false)
1✔
1786
        doc->writeTextElement(KXMLQLCVCWidgetKey, m_stopKeySequence.toString());
1✔
1787
    saveXMLInput(doc, inputSource(stopInputSourceId));
1✔
1788
    doc->writeEndElement();
1✔
1789

1790
    /* Crossfade cue list */
1791
    if (sideFaderMode() != None)
1✔
1792
        doc->writeTextElement(KXMLQLCVCCueListSlidersMode, faderModeToString(sideFaderMode()));
1✔
1793

1794
    QSharedPointer<QLCInputSource> cf1Src = inputSource(sideFaderInputSourceId);
1✔
1795
    if (!cf1Src.isNull() && cf1Src->isValid())
1✔
1796
    {
1797
        doc->writeStartElement(KXMLQLCVCCueListCrossfadeLeft);
×
1798
        saveXMLInput(doc, cf1Src);
×
1799
        doc->writeEndElement();
×
1800
    }
1801

1802
    /* End the <CueList> tag */
1803
    doc->writeEndElement();
1✔
1804

1805
    return true;
2✔
1806
}
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

© 2025 Coveralls, Inc