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

mcallegari / qlcplus / 6383149330

02 Oct 2023 05:00PM UTC coverage: 28.056% (-0.001%) from 28.057%
6383149330

push

github

mcallegari
vcslider: fix switching from playback to submaster mode (fix #1458)

1 of 1 new or added line in 1 file covered. (100.0%)

15332 of 54647 relevant lines covered (28.06%)

20322.98 hits per line

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

17.21
/ui/src/virtualconsole/vcslider.cpp
1
/*
2
  Q Light Controller Plus
3
  vcslider.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Stefan Krumm
7
                Massimo Callegari
8

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

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

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

22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QWidgetAction>
25
#include <QVBoxLayout>
26
#include <QHBoxLayout>
27
#include <QMessageBox>
28
#include <QPaintEvent>
29
#include <QSettings>
30
#include <QPainter>
31
#include <QString>
32
#include <QSlider>
33
#include <QTimer>
34
#include <QDebug>
35
#include <QLabel>
36
#include <math.h>
37
#include <QMenu>
38
#include <QSize>
39
#include <QPen>
40

41
#include "vcsliderproperties.h"
42
#include "vcpropertieseditor.h"
43
#include "qlcinputchannel.h"
44
#include "virtualconsole.h"
45
#include "qlcinputsource.h"
46
#include "mastertimer.h"
47
#include "collection.h"
48
#include "inputpatch.h"
49
#include "qlcmacros.h"
50
#include "universe.h"
51
#include "vcslider.h"
52
#include "qlcfile.h"
53
#include "apputil.h"
54
#include "chaser.h"
55
#include "scene.h"
56
#include "efx.h"
57
#include "doc.h"
58

59
/** Number of DMXSource cycles to wait to consider a
60
 *  playback value change stable */
61
#define PLAYBACK_CHANGE_THRESHOLD   5  // roughly this is 100ms
62

63
/** +/- value range to catch the slider for external
64
 *  controllers with no feedback support */
65
#define VALUE_CATCHING_THRESHOLD    4
66

67
const quint8 VCSlider::sliderInputSourceId = 0;
68
const quint8 VCSlider::overrideResetInputSourceId = 1;
69

70
const QSize VCSlider::defaultSize(QSize(60, 200));
71

72
const QString submasterStyleSheet =
73
    SLIDER_SS_COMMON
74

75
    "QSlider::handle:vertical { "
76
    "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #4c4c4c, stop:0.45 #2c2c2c, stop:0.50 #000, stop:0.55 #111111, stop:1 #131313);"
77
    "border: 1px solid #5c5c5c;"
78
    "border-radius: 4px; margin: 0 -4px; height: 20px; }"
79

80
    "QSlider::handle:vertical:hover {"
81
    "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6c6c6c, stop:0.45 #4c4c4c, stop:0.50 #ffff00, stop:0.55 #313131, stop:1 #333333);"
82
    "border: 1px solid #000; }"
83

84
    "QSlider::add-page:vertical { background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #77DD73, stop: 1 #A5EC98 );"
85
    "border: 1px solid #5288A7; margin: 0 9px; }";
86

87
/*****************************************************************************
88
 * Initialization
89
 *****************************************************************************/
90

91
VCSlider::VCSlider(QWidget *parent, Doc *doc)
1✔
92
    : VCWidget(parent, doc)
93
    , m_valueDisplayStyle(ExactValue)
94
    , m_catchValues(false)
95
    , m_levelLowLimit(0)
96
    , m_levelHighLimit(UCHAR_MAX)
97
    , m_levelValueChanged(false)
98
    , m_levelValue(0)
99
    , m_monitorEnabled(false)
100
    , m_monitorValue(0)
101
    , m_playbackFunction(Function::invalidId())
2✔
102
    , m_playbackValue(0)
103
    , m_playbackChangeCounter(0)
104
    , m_externalMovement(false)
105
    , m_widgetMode(WSlider)
106
    , m_cngType(ClickAndGoWidget::None)
107
    , m_isOverriding(false)
108
    , m_lastInputValue(-1)
1✔
109
{
110
    /* Set the class name "VCSlider" as the object name as well */
111
    setObjectName(VCSlider::staticMetaObject.className());
1✔
112

113
    m_hbox = NULL;
1✔
114
    m_topLabel = NULL;
1✔
115
    m_slider = NULL;
1✔
116
    m_bottomLabel = NULL;
1✔
117

118
    setType(VCWidget::SliderWidget);
1✔
119
    setCaption(QString());
1✔
120
    setFrameStyle(KVCFrameStyleSunken);
1✔
121

122
    /* Main VBox */
123
    new QVBoxLayout(this);
1✔
124

125
    /* Top label */
126
    m_topLabel = new QLabel(this);
1✔
127
    m_topLabel->setAlignment(Qt::AlignHCenter);
1✔
128

129
    layout()->addWidget(m_topLabel);
1✔
130

131
    /* Slider's HBox |stretch|slider|stretch| */
132
    m_hbox = new QHBoxLayout();
1✔
133

134
    /* Put stretchable space before the slider (to its left side) */
135
    m_hbox->addStretch();
1✔
136

137
    /* The slider */
138
    m_slider = new ClickAndGoSlider(this);
1✔
139

140
    m_hbox->addWidget(m_slider);
1✔
141
    m_slider->setRange(0, 255);
1✔
142
    m_slider->setPageStep(1);
1✔
143
    m_slider->setInvertedAppearance(false);
1✔
144
    m_slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
1✔
145
    m_slider->setMinimumWidth(32);
1✔
146
    m_slider->setMaximumWidth(80);
1✔
147
    m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
1✔
148

149
    connect(m_slider, SIGNAL(valueChanged(int)),
1✔
150
            this, SLOT(slotSliderMoved(int)));
151
    connect(this, SIGNAL(requestSliderUpdate(int)),
2✔
152
            m_slider, SLOT(setValue(int)));
1✔
153

154
    /* Put stretchable space after the slider (to its right side) */
155
    m_hbox->addStretch();
1✔
156

157
    layout()->addItem(m_hbox);
1✔
158

159
    /* Click & Go button */
160
    m_cngButton = new QToolButton(this);
1✔
161
    m_cngButton->setFixedSize(48, 48);
1✔
162
    m_cngButton->setIconSize(QSize(42, 42));
1✔
163
    m_menu = new QMenu(this);
1✔
164
    QWidgetAction* action = new QWidgetAction(this);
1✔
165
    m_cngWidget = new ClickAndGoWidget();
1✔
166
    action->setDefaultWidget(m_cngWidget);
1✔
167
    m_menu->addAction(action);
1✔
168
    m_cngButton->setMenu(m_menu);
1✔
169
    m_cngButton->setPopupMode(QToolButton::InstantPopup);
1✔
170
    layout()->addWidget(m_cngButton);
1✔
171
    layout()->setAlignment(m_cngButton, Qt::AlignHCenter);
1✔
172
    m_cngButton->hide();
1✔
173

174
    connect(m_cngWidget, SIGNAL(levelChanged(uchar)),
1✔
175
            this, SLOT(slotClickAndGoLevelChanged(uchar)));
176
    connect(m_cngWidget, SIGNAL(colorChanged(QRgb)),
1✔
177
            this, SLOT(slotClickAndGoColorChanged(QRgb)));
178
    connect(m_cngWidget, SIGNAL(levelAndPresetChanged(uchar,QImage)),
1✔
179
            this, SLOT(slotClickAndGoLevelAndPresetChanged(uchar, QImage)));
180
    connect(this, SIGNAL(monitorDMXValueChanged(int)),
1✔
181
            this, SLOT(slotMonitorDMXValueChanged(int)));
182

183
    m_resetButton = NULL;
1✔
184

185
    /* Bottom label */
186
    m_bottomLabel = new QLabel(this);
1✔
187
    layout()->addWidget(m_bottomLabel);
1✔
188
    m_bottomLabel->setAlignment(Qt::AlignCenter);
1✔
189
    m_bottomLabel->setWordWrap(true);
1✔
190
    m_bottomLabel->hide();
1✔
191

192
    setMinimumSize(20, 20);
1✔
193
    QSettings settings;
2✔
194
    QVariant var = settings.value(SETTINGS_SLIDER_SIZE);
2✔
195
    if (var.isValid() == true)
1✔
196
        resize(var.toSize());
×
197
    else
198
        resize(VCSlider::defaultSize);
1✔
199

200
    /* Initialize to playback mode by default */
201
    setInvertedAppearance(false);
1✔
202
    m_sliderMode = SliderMode(-1); // avoid use of uninitialized value
1✔
203
    setSliderMode(Playback);
1✔
204

205
    /* Update the slider according to current mode */
206
    slotModeChanged(m_doc->mode());
1✔
207
    setLiveEdit(m_liveEdit);
1✔
208

209
    /* Listen to fixture removals so that LevelChannels can be removed when
210
       they no longer point to an existing fixture->channel */
211
    connect(m_doc, SIGNAL(fixtureRemoved(quint32)),
1✔
212
            this, SLOT(slotFixtureRemoved(quint32)));
213
}
1✔
214

215
VCSlider::~VCSlider()
2✔
216
{
217
    /* When application exits these are already NULL and unregistration
218
       is no longer necessary. But a normal deletion of a VCSlider in
219
       design mode must unregister the slider. */
220
    m_doc->masterTimer()->unregisterDMXSource(this);
1✔
221

222
    // request to delete all the active faders
223
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
2✔
224
    {
225
        if (!fader.isNull())
×
226
            fader->requestDelete();
×
227
    }
228
    m_fadersMap.clear();
1✔
229
}
2✔
230

231
void VCSlider::setID(quint32 id)
×
232
{
233
    VCWidget::setID(id);
×
234

235
    if (caption().isEmpty())
×
236
        setCaption(tr("Slider %1").arg(id));
×
237
}
×
238

239
/*****************************************************************************
240
 * Clipboard
241
 *****************************************************************************/
242

243
VCWidget* VCSlider::createCopy(VCWidget* parent)
×
244
{
245
    Q_ASSERT(parent != NULL);
×
246

247
    VCSlider* slider = new VCSlider(parent, m_doc);
×
248
    if (slider->copyFrom(this) == false)
×
249
    {
250
        delete slider;
×
251
        slider = NULL;
×
252
    }
253

254
    return slider;
×
255
}
256

257
bool VCSlider::copyFrom(const VCWidget* widget)
×
258
{
259
    const VCSlider* slider = qobject_cast<const VCSlider*> (widget);
×
260
    if (slider == NULL)
×
261
        return false;
×
262

263
    /* Copy widget style */
264
    setWidgetStyle(slider->widgetStyle());
×
265

266
    /* Copy level stuff */
267
    setLevelLowLimit(slider->levelLowLimit());
×
268
    setLevelHighLimit(slider->levelHighLimit());
×
269
    m_levelChannels = slider->m_levelChannels;
×
270

271
    /* Copy playback stuff */
272
    m_playbackFunction = slider->m_playbackFunction;
×
273

274
    /* Copy slider appearance */
275
    setValueDisplayStyle(slider->valueDisplayStyle());
×
276
    setInvertedAppearance(slider->invertedAppearance());
×
277

278
    /* Copy Click & Go feature */
279
    setClickAndGoType(slider->clickAndGoType());
×
280

281
    /* Copy mode & current value */
282
    setSliderMode(slider->sliderMode());
×
283
    setSliderValue(slider->sliderValue());
×
284

285
    /* Copy monitor mode */
286
    setChannelsMonitorEnabled(slider->channelsMonitorEnabled());
×
287

288
    /* Copy common stuff */
289
    return VCWidget::copyFrom(widget);
×
290
}
291

292
/*****************************************************************************
293
 * GUI
294
 *****************************************************************************/
295

296
void VCSlider::setCaption(const QString& text)
1✔
297
{
298
    VCWidget::setCaption(text);
1✔
299

300
    if (m_bottomLabel != NULL)
1✔
301
        setBottomLabelText(text);
×
302
}
1✔
303

304
void VCSlider::enableWidgetUI(bool enable)
1✔
305
{
306
    m_topLabel->setEnabled(enable);
1✔
307
    if (m_slider)
1✔
308
        m_slider->setEnabled(enable);
1✔
309
    m_bottomLabel->setEnabled(enable);
1✔
310
    m_cngButton->setEnabled(enable);
1✔
311
    if (m_resetButton)
1✔
312
        m_resetButton->setEnabled(enable);
×
313
    if (enable == false)
1✔
314
        m_lastInputValue = -1;
1✔
315
}
1✔
316

317
void VCSlider::hideEvent(QHideEvent *)
×
318
{
319
    m_lastInputValue = -1;
×
320
}
×
321

322
/*****************************************************************************
323
 * Properties
324
 *****************************************************************************/
325

326
void VCSlider::editProperties()
×
327
{
328
    VCSliderProperties prop(this, m_doc);
×
329
    if (prop.exec() == QDialog::Accepted)
×
330
    {
331
        m_doc->setModified();
×
332
        if (m_cngType == ClickAndGoWidget::None)
×
333
            m_cngButton->hide();
×
334
        else
335
            m_cngButton->show();
×
336
    }
337
}
×
338

339
/*****************************************************************************
340
 * QLC Mode
341
 *****************************************************************************/
342

343
void VCSlider::slotModeChanged(Doc::Mode mode)
1✔
344
{
345
    if (mode == Doc::Operate)
1✔
346
    {
347
        enableWidgetUI(true);
×
348
        if (m_sliderMode == Level || m_sliderMode == Playback)
×
349
        {
350
            m_doc->masterTimer()->registerDMXSource(this);
×
351
            if (m_sliderMode == Level)
×
352
                m_levelValueChanged = true;
×
353
        }
354
    }
355
    else
356
    {
357
        enableWidgetUI(false);
1✔
358
        if (m_sliderMode == Level || m_sliderMode == Playback)
1✔
359
        {
360
            m_doc->masterTimer()->unregisterDMXSource(this);
1✔
361
            // request to delete all the active faders
362
            foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
2✔
363
            {
364
                if (!fader.isNull())
×
365
                    fader->requestDelete();
×
366
            }
367
            m_fadersMap.clear();
1✔
368
        }
369
    }
370

371
    VCWidget::slotModeChanged(mode);
1✔
372
}
1✔
373

374
/*****************************************************************************
375
 * Value display style
376
 *****************************************************************************/
377

378
QString VCSlider::valueDisplayStyleToString(VCSlider::ValueDisplayStyle style)
×
379
{
380
    switch (style)
×
381
    {
382
    case ExactValue:
×
383
        return KXMLQLCVCSliderValueDisplayStyleExact;
×
384
    case PercentageValue:
×
385
        return KXMLQLCVCSliderValueDisplayStylePercentage;
×
386
    default:
×
387
        return QString("Unknown");
×
388
    };
389
}
390

391
VCSlider::ValueDisplayStyle VCSlider::stringToValueDisplayStyle(QString style)
×
392
{
393
    if (style == KXMLQLCVCSliderValueDisplayStyleExact)
×
394
        return ExactValue;
×
395
    else if (style == KXMLQLCVCSliderValueDisplayStylePercentage)
×
396
        return PercentageValue;
×
397
    else
398
        return ExactValue;
×
399
}
400

401
void VCSlider::setValueDisplayStyle(VCSlider::ValueDisplayStyle style)
×
402
{
403
    m_valueDisplayStyle = style;
×
404
    if (m_slider)
×
405
        setTopLabelText(m_slider->value());
×
406
}
×
407

408
VCSlider::ValueDisplayStyle VCSlider::valueDisplayStyle() const
2✔
409
{
410
    return m_valueDisplayStyle;
2✔
411
}
412

413
/*****************************************************************************
414
 * Inverted appearance
415
 *****************************************************************************/
416

417
bool VCSlider::invertedAppearance() const
×
418
{
419
    if (m_slider)
×
420
        return m_slider->invertedAppearance();
×
421

422
    return false;
×
423
}
424

425
void VCSlider::setInvertedAppearance(bool invert)
2✔
426
{
427
    if (m_slider)
2✔
428
    {
429
        m_slider->setInvertedAppearance(invert);
2✔
430
        m_slider->setInvertedControls(invert);
2✔
431
    }
432
}
2✔
433

434
/*********************************************************************
435
 * Value catching feature
436
 *********************************************************************/
437

438
bool VCSlider::catchValues() const
×
439
{
440
    return m_catchValues;
×
441
}
442

443
void VCSlider::setCatchValues(bool enable)
×
444
{
445
    if (enable == m_catchValues)
×
446
        return;
×
447

448
    m_catchValues = enable;
×
449
}
450

451
/*****************************************************************************
452
 * Slider Mode
453
 *****************************************************************************/
454

455
QString VCSlider::sliderModeToString(SliderMode mode)
×
456
{
457
    switch (mode)
×
458
    {
459
        case Level: return QString("Level"); break;
×
460
        case Playback: return QString("Playback"); break;
×
461
        case Submaster: return QString("Submaster"); break;
×
462
        default: return QString("Unknown"); break;
×
463
    }
464
}
465

466
VCSlider::SliderMode VCSlider::stringToSliderMode(const QString& mode)
×
467
{
468
    if (mode == QString("Level"))
×
469
        return Level;
×
470
    else  if (mode == QString("Playback"))
×
471
       return Playback;
×
472
    else //if (mode == QString("Submaster"))
473
        return Submaster;
×
474
}
475

476
VCSlider::SliderMode VCSlider::sliderMode() const
×
477
{
478
    return m_sliderMode;
×
479
}
480

481
void VCSlider::setSliderMode(SliderMode mode)
2✔
482
{
483
    Q_ASSERT(mode >= Level && mode <= Submaster);
2✔
484

485
    m_sliderMode = mode;
2✔
486

487
    if (mode == Level)
2✔
488
    {
489
        /* Set the slider range */
490
        if (m_slider)
×
491
        {
492
            m_slider->setRange(levelLowLimit(), levelHighLimit());
×
493
            m_slider->setValue(levelValue());
×
494
            if (m_widgetMode == WSlider)
×
495
                m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
×
496
        }
497

498
        m_bottomLabel->show();
×
499
        if (m_cngType != ClickAndGoWidget::None)
×
500
        {
501
            setClickAndGoType(m_cngType);
×
502
            setupClickAndGoWidget();
×
503
            m_cngButton->show();
×
504
            if (m_slider)
×
505
                setClickAndGoWidgetFromLevel(m_slider->value());
×
506
        }
507

508
        if (m_doc->mode() == Doc::Operate)
×
509
            m_doc->masterTimer()->registerDMXSource(this);
×
510
    }
511
    else if (mode == Playback)
2✔
512
    {
513
        m_bottomLabel->show();
2✔
514
        m_cngButton->hide();
2✔
515
        m_monitorEnabled = false;
2✔
516

517
        uchar level = playbackValue();
2✔
518
        if (m_slider)
2✔
519
        {
520
            m_slider->setRange(0, UCHAR_MAX);
2✔
521
            m_slider->setValue(level);
2✔
522
            if (m_widgetMode == WSlider)
2✔
523
                m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
2✔
524
        }
525
        slotSliderMoved(level);
2✔
526

527
        if (m_doc->mode() == Doc::Operate)
2✔
528
            m_doc->masterTimer()->registerDMXSource(this);
×
529
        setPlaybackFunction(this->m_playbackFunction);
2✔
530
    }
531
    else if (mode == Submaster)
×
532
    {
533
        m_monitorEnabled = false;
×
534
        setPlaybackFunction(Function::invalidId());
×
535

536
        if (m_slider)
×
537
        {
538
            m_slider->setRange(0, UCHAR_MAX);
×
539
            m_slider->setValue(levelValue());
×
540
            if (m_widgetMode == WSlider)
×
541
                m_slider->setStyleSheet(submasterStyleSheet);
×
542
        }
543
        if (m_doc->mode() == Doc::Operate)
×
544
            m_doc->masterTimer()->unregisterDMXSource(this);
×
545
    }
546
}
2✔
547

548
/*****************************************************************************
549
 * Level
550
 *****************************************************************************/
551

552
void VCSlider::addLevelChannel(quint32 fixture, quint32 channel)
×
553
{
554
    LevelChannel lch(fixture, channel);
×
555

556
    if (m_levelChannels.contains(lch) == false)
×
557
    {
558
        m_levelChannels.append(lch);
×
559
        std::sort(m_levelChannels.begin(), m_levelChannels.end());
×
560
    }
561
}
×
562

563
void VCSlider::removeLevelChannel(quint32 fixture, quint32 channel)
×
564
{
565
    LevelChannel lch(fixture, channel);
×
566
    m_levelChannels.removeAll(lch);
×
567
}
×
568

569
void VCSlider::clearLevelChannels()
×
570
{
571
    m_levelChannels.clear();
×
572
}
×
573

574
QList <VCSlider::LevelChannel> VCSlider::levelChannels()
×
575
{
576
    return m_levelChannels;
×
577
}
578

579
void VCSlider::setLevelLowLimit(uchar value)
×
580
{
581
    m_levelLowLimit = value;
×
582
}
×
583

584
uchar VCSlider::levelLowLimit() const
×
585
{
586
    return m_levelLowLimit;
×
587
}
588

589
void VCSlider::setLevelHighLimit(uchar value)
×
590
{
591
    m_levelHighLimit = value;
×
592
}
×
593

594
uchar VCSlider::levelHighLimit() const
×
595
{
596
    return m_levelHighLimit;
×
597
}
598

599
void VCSlider::setChannelsMonitorEnabled(bool enable)
×
600
{
601
    m_monitorEnabled = enable;
×
602

603
    if (m_resetButton != NULL)
×
604
    {
605
        disconnect(m_resetButton, SIGNAL(clicked(bool)),
×
606
                this, SLOT(slotResetButtonClicked()));
607
        delete m_resetButton;
×
608
        m_resetButton = NULL;
×
609
    }
610

611
    if (enable)
×
612
    {
613
        m_resetButton = new QToolButton(this);
×
614
        m_cngButton->setFixedSize(32, 32);
×
615
        m_resetButton->setIconSize(QSize(32, 32));
×
616
        m_resetButton->setStyle(AppUtil::saneStyle());
×
617
        m_resetButton->setIcon(QIcon(":/fileclose.png"));
×
618
        m_resetButton->setToolTip(tr("Reset channels override"));
×
619
        layout()->addWidget(m_resetButton);
×
620
        layout()->setAlignment(m_resetButton, Qt::AlignHCenter);
×
621

622
        connect(m_resetButton, SIGNAL(clicked(bool)),
×
623
                this, SLOT(slotResetButtonClicked()));
624
        m_resetButton->show();
×
625
        setSliderShadowValue(m_monitorValue);
×
626
    }
627
    else
628
    {
629
        setSliderShadowValue(-1);
×
630
    }
631
}
×
632

633
bool VCSlider::channelsMonitorEnabled() const
×
634
{
635
    return m_monitorEnabled;
×
636
}
637

638
void VCSlider::setLevelValue(uchar value, bool external)
×
639
{
640
    QMutexLocker locker(&m_levelValueMutex);
×
641
    m_levelValue = CLAMP(value, levelLowLimit(), levelHighLimit());
×
642
    if (m_monitorEnabled == true)
×
643
        m_monitorValue = m_levelValue;
×
644
    if (m_slider->isSliderDown() || external)
×
645
        m_levelValueChanged = true;
×
646
}
×
647

648
uchar VCSlider::levelValue() const
×
649
{
650
    return m_levelValue;
×
651
}
652

653
void VCSlider::slotFixtureRemoved(quint32 fxi_id)
×
654
{
655
    QMutableListIterator <LevelChannel> it(m_levelChannels);
×
656
    while (it.hasNext() == true)
×
657
    {
658
        it.next();
×
659
        if (it.value().fixture == fxi_id)
×
660
            it.remove();
×
661
    }
662
}
×
663

664
void VCSlider::slotMonitorDMXValueChanged(int value)
×
665
{
666
    if (value == sliderValue())
×
667
        return;
×
668

669
    m_monitorValue = value;
×
670

671
    if (m_isOverriding == false)
×
672
    {
673
        {
674
            QMutexLocker locker(&m_levelValueMutex);
×
675
            m_levelValue = m_monitorValue;
×
676
        }
677

678
        if (m_slider)
×
679
            m_slider->blockSignals(true);
×
680
        setSliderValue(value, false);
×
681
        setTopLabelText(sliderValue());
×
682
        if (m_slider)
×
683
            m_slider->blockSignals(false);
×
684
    }
685
    setSliderShadowValue(value);
×
686
    updateFeedback();
×
687
}
688

689
void VCSlider::slotUniverseWritten(quint32 idx, const QByteArray &universeData)
×
690
{
691
    if (m_levelValueChanged)
×
692
        return;
×
693

694
    bool mixedDMXlevels = false;
×
695
    int monitorSliderValue = -1;
×
696
    QListIterator <LevelChannel> it(m_levelChannels);
×
697

698
    while (it.hasNext() == true)
×
699
    {
700
        LevelChannel lch(it.next());
×
701
        Fixture* fxi = m_doc->fixture(lch.fixture);
×
702
        if (fxi == NULL || fxi->universe() != idx)
×
703
            continue;
×
704

705
        if (lch.channel >= fxi->channels() ||
×
706
            fxi->address() + lch.channel >= (quint32)universeData.length())
×
707
            continue;
×
708

709
        quint32 dmx_ch = fxi->address() + lch.channel;
×
710
        uchar chValue = universeData.at(dmx_ch);
×
711
        if (monitorSliderValue == -1)
×
712
        {
713
            monitorSliderValue = chValue;
×
714
            //qDebug() << "Monitor DMX value:" << monitorSliderValue << "level value:" << m_levelValue;
715
        }
716
        else
717
        {
718
            if (chValue != (uchar)monitorSliderValue)
×
719
            {
720
                mixedDMXlevels = true;
×
721
                // no need to proceed further as mixed values cannot
722
                // be represented by one single slider
723
                break;
×
724
            }
725
        }
726
    }
727

728
    // check if all the DMX channels controlled by this slider
729
    // have the same value. If so, move the widget slider or knob
730
    // to the detected position
731
    if (mixedDMXlevels == false &&
×
732
        monitorSliderValue != m_monitorValue)
×
733
    {
734
        emit monitorDMXValueChanged(monitorSliderValue);
×
735

736
        if (m_isOverriding == false)
×
737
        {
738
            // return here. At the next call of this method,
739
            // the monitor level will kick in
740
            return;
×
741
        }
742
    }
743
}
744

745
/*********************************************************************
746
 * Click & Go
747
 *********************************************************************/
748

749
void VCSlider::setClickAndGoType(ClickAndGoWidget::ClickAndGo type)
×
750
{
751
    m_cngType = type;
×
752
}
×
753

754
ClickAndGoWidget::ClickAndGo VCSlider::clickAndGoType() const
×
755
{
756
    return m_cngType;
×
757
}
758

759
void VCSlider::setupClickAndGoWidget()
×
760
{
761
    if (m_cngWidget != NULL)
×
762
    {
763
        qDebug() << Q_FUNC_INFO << "Level channel: " << m_levelChannels.size() << "type: " << m_cngType;
×
764
        if (m_cngType == ClickAndGoWidget::Preset && m_levelChannels.size() > 0)
×
765
        {
766
            LevelChannel lChan = m_levelChannels.first();
×
767
            Fixture *fxi = m_doc->fixture(lChan.fixture);
×
768
            if (fxi != NULL)
×
769
            {
770
                const QLCChannel *chan = fxi->channel(lChan.channel);
×
771
                m_cngWidget->setType(m_cngType, chan);
×
772
            }
773
        }
774
        else
775
            m_cngWidget->setType(m_cngType, NULL);
×
776
    }
777
}
×
778

779
ClickAndGoWidget *VCSlider::getClickAndGoWidget()
×
780
{
781
    return m_cngWidget;
×
782
}
783

784
void VCSlider::setClickAndGoWidgetFromLevel(uchar level)
×
785
{
786
    if (m_cngType == ClickAndGoWidget::None || m_cngWidget == NULL)
×
787
        return;
×
788

789
    if (m_cngType == ClickAndGoWidget::RGB || m_cngType == ClickAndGoWidget::CMY)
×
790
    {
791
        QPixmap px(42, 42);
×
792
        float f = 0;
×
793
        if (m_slider)
×
794
            f = SCALE(float(level), float(m_slider->minimum()),
×
795
                      float(m_slider->maximum()), float(0), float(200));
796

797
        if ((uchar)f == 0)
×
798
        {
799
            px.fill(Qt::black);
×
800
        }
801
        else
802
        {
803
            QColor modColor = m_cngRGBvalue.lighter((uchar)f);
×
804
            px.fill(modColor);
×
805
        }
806
        m_cngButton->setIcon(px);
×
807
    }
808
    else
809
        m_cngButton->setIcon(QPixmap::fromImage(m_cngWidget->getImageFromValue(level)));
×
810
}
811

812
void VCSlider::slotClickAndGoLevelChanged(uchar level)
×
813
{
814
    setSliderValue(level);
×
815
    updateFeedback();
×
816

817
    QColor col = m_cngWidget->getColorAt(level);
×
818
    QPixmap px(42, 42);
×
819
    px.fill(col);
×
820
    m_cngButton->setIcon(px);
×
821
    m_levelValueChanged = true;
×
822
}
×
823

824
void VCSlider::slotClickAndGoColorChanged(QRgb color)
×
825
{
826
    QColor col(color);
×
827
    m_cngRGBvalue = col;
×
828
    QPixmap px(42, 42);
×
829
    px.fill(col);
×
830
    m_cngButton->setIcon(px);
×
831

832
    // place the slider half way to reach white@255 and black@0
833
    setSliderValue(128);
×
834
    updateFeedback();
×
835

836
    // let's force a value change to cover all the HTP/LTP cases
837
    m_levelValueChanged = true;
×
838
}
×
839

840
void VCSlider::slotClickAndGoLevelAndPresetChanged(uchar level, QImage img)
×
841
{
842
    setSliderValue(level);
×
843
    updateFeedback();
×
844

845
    QPixmap px = QPixmap::fromImage(img);
×
846
    m_cngButton->setIcon(px);
×
847
    m_levelValueChanged = true;
×
848
}
×
849

850
/*********************************************************************
851
 * Override reset button
852
 *********************************************************************/
853

854
void VCSlider::setOverrideResetKeySequence(const QKeySequence &keySequence)
×
855
{
856
    m_overrideResetKeySequence = QKeySequence(keySequence);
×
857
}
×
858

859
QKeySequence VCSlider::overrideResetKeySequence() const
×
860
{
861
    return m_overrideResetKeySequence;
×
862
}
863

864
void VCSlider::slotResetButtonClicked()
×
865
{
866
    m_isOverriding = false;
×
867
    m_resetButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
868
                                 .arg(m_slider->palette().window().color().name()));
×
869

870
    // request to delete all the active fader channels
871
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
872
    {
873
        if (!fader.isNull())
×
874
            fader->removeAll();
×
875
    }
876

877
    emit monitorDMXValueChanged(m_monitorValue);
×
878
}
×
879

880
void VCSlider::slotKeyPressed(const QKeySequence &keySequence)
×
881
{
882
    if (isEnabled() == false)
×
883
        return;
×
884

885
    if (m_overrideResetKeySequence == keySequence)
×
886
        slotResetButtonClicked();
×
887
}
888

889
/*****************************************************************************
890
 * Playback
891
 *****************************************************************************/
892

893
void VCSlider::setPlaybackFunction(quint32 fid)
2✔
894
{
895
    Function* old = m_doc->function(m_playbackFunction);
2✔
896
    if (old != NULL)
2✔
897
    {
898
        /* Get rid of old function connections */
899
        disconnect(old, SIGNAL(running(quint32)),
×
900
                this, SLOT(slotPlaybackFunctionRunning(quint32)));
901
        disconnect(old, SIGNAL(stopped(quint32)),
×
902
                this, SLOT(slotPlaybackFunctionStopped(quint32)));
903
        disconnect(old, SIGNAL(attributeChanged(int, qreal)),
×
904
                this, SLOT(slotPlaybackFunctionIntensityChanged(int, qreal)));
905
        if (old->type() == Function::SceneType)
×
906
        {
907
            disconnect(old, SIGNAL(flashing(quint32,bool)),
×
908
                       this, SLOT(slotPlaybackFunctionFlashing(quint32,bool)));
909
        }
910
    }
911

912
    Function* function = m_doc->function(fid);
2✔
913
    if (function != NULL)
2✔
914
    {
915
        /* Connect to the new function */
916
        connect(function, SIGNAL(running(quint32)),
×
917
                this, SLOT(slotPlaybackFunctionRunning(quint32)));
918
        connect(function, SIGNAL(stopped(quint32)),
×
919
                this, SLOT(slotPlaybackFunctionStopped(quint32)));
920
        connect(function, SIGNAL(attributeChanged(int, qreal)),
×
921
                this, SLOT(slotPlaybackFunctionIntensityChanged(int, qreal)));
922
        if (function->type() == Function::SceneType)
×
923
        {
924
            connect(function, SIGNAL(flashing(quint32,bool)),
×
925
                    this, SLOT(slotPlaybackFunctionFlashing(quint32,bool)));
926
        }
927

928
        m_playbackFunction = fid;
×
929
    }
930
    else
931
    {
932
        /* No function attachment */
933
        m_playbackFunction = Function::invalidId();
2✔
934
    }
935
}
2✔
936

937
quint32 VCSlider::playbackFunction() const
×
938
{
939
    return m_playbackFunction;
×
940
}
941

942
void VCSlider::setPlaybackValue(uchar value)
×
943
{
944
    if (m_externalMovement == true || value == m_playbackValue)
×
945
        return;
×
946

947
    QMutexLocker locker(&m_playbackValueMutex);
×
948
    m_playbackValue = value;
×
949
    m_playbackChangeCounter = 5;
×
950
}
951

952
uchar VCSlider::playbackValue() const
2✔
953
{
954
    return m_playbackValue;
2✔
955
}
956

957
void VCSlider::notifyFunctionStarting(quint32 fid, qreal functionIntensity)
×
958
{
959
    if (mode() == Doc::Design || sliderMode() != Playback)
×
960
        return;
×
961

962
    if (fid == playbackFunction())
×
963
        return;
×
964

965
    if (m_slider != NULL)
×
966
    {
967
        int value = SCALE(1.0 - functionIntensity, 0, 1.0,
×
968
                          m_slider->minimum(), m_slider->maximum());
969
        if (m_slider->value() > value)
×
970
        {
971
            m_externalMovement = true;
×
972
            m_slider->setValue(value);
×
973
            m_externalMovement = false;
×
974

975
            Function* function = m_doc->function(m_playbackFunction);
×
976
            if (function != NULL)
×
977
            {
978
                qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
979
                adjustFunctionIntensity(function, pIntensity * intensity());
×
980
                if (value == 0 && !function->stopped())
×
981
                    function->stop(functionParent());
×
982
            }
983
        }
984
    }
985
}
986

987
void VCSlider::slotPlaybackFunctionRunning(quint32 fid)
×
988
{
989
    Q_UNUSED(fid);
990
}
×
991

992
void VCSlider::slotPlaybackFunctionStopped(quint32 fid)
×
993
{
994
    if (fid != playbackFunction())
×
995
        return;
×
996

997
    m_externalMovement = true;
×
998
    if (m_slider)
×
999
        m_slider->setValue(0);
×
1000
    resetIntensityOverrideAttribute();
×
1001
    updateFeedback();
×
1002
    m_externalMovement = false;
×
1003
}
1004

1005
void VCSlider::slotPlaybackFunctionIntensityChanged(int attrIndex, qreal fraction)
×
1006
{
1007
    //qDebug() << "Function intensity changed" << attrIndex << fraction << m_playbackChangeCounter;
1008

1009
    if (attrIndex != Function::Intensity || m_playbackChangeCounter)
×
1010
        return;
×
1011

1012
    m_externalMovement = true;
×
1013
    if (m_slider)
×
1014
        m_slider->setValue(int(floor((qreal(m_slider->maximum()) * fraction) + 0.5)));
×
1015
    updateFeedback();
×
1016
    m_externalMovement = false;
×
1017
}
1018

1019
void VCSlider::slotPlaybackFunctionFlashing(quint32 fid, bool flashing)
×
1020
{
1021
    if (fid != playbackFunction())
×
1022
        return;
×
1023

1024
    m_externalMovement = true;
×
1025
    if (m_slider)
×
1026
        m_slider->setValue(flashing ? m_slider->maximum() : m_slider->minimum());
×
1027
    updateFeedback();
×
1028
    m_externalMovement = false;
×
1029
}
1030

1031
FunctionParent VCSlider::functionParent() const
×
1032
{
1033
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
1034
}
1035

1036
/*********************************************************************
1037
 * Submaster
1038
 *********************************************************************/
1039

1040
void VCSlider::emitSubmasterValue()
×
1041
{
1042
    Q_ASSERT(sliderMode() == Submaster);
×
1043

1044
    emit submasterValueChanged(SCALE(float(m_levelValue), float(0),
×
1045
                float(UCHAR_MAX), float(0), float(1)) * intensity());
×
1046
}
×
1047

1048
/*****************************************************************************
1049
 * DMXSource
1050
 *****************************************************************************/
1051

1052
void VCSlider::writeDMX(MasterTimer *timer, QList<Universe *> universes)
×
1053
{
1054
    if (sliderMode() == Level)
×
1055
        writeDMXLevel(timer, universes);
×
1056
    else if (sliderMode() == Playback)
×
1057
        writeDMXPlayback(timer, universes);
×
1058
}
×
1059

1060
void VCSlider::writeDMXLevel(MasterTimer *timer, QList<Universe *> universes)
×
1061
{
1062
    Q_UNUSED(timer);
1063

1064
    QMutexLocker locker(&m_levelValueMutex);
×
1065

1066
    uchar modLevel = m_levelValue;
×
1067
    int r = 0, g = 0, b = 0, c = 0, m = 0, y = 0;
×
1068

1069
    if (m_cngType == ClickAndGoWidget::RGB)
×
1070
    {
1071
        float f = 0;
×
1072
        if (m_slider)
×
1073
            f = SCALE(float(m_levelValue), float(m_slider->minimum()),
×
1074
                      float(m_slider->maximum()), float(0), float(200));
1075

1076
        if (uchar(f) != 0)
×
1077
        {
1078
            QColor modColor = m_cngRGBvalue.lighter(uchar(f));
×
1079
            r = modColor.red();
×
1080
            g = modColor.green();
×
1081
            b = modColor.blue();
×
1082
        }
1083
    }
1084
    else if (m_cngType == ClickAndGoWidget::CMY)
×
1085
    {
1086
        float f = 0;
×
1087
        if (m_slider)
×
1088
            f = SCALE(float(m_levelValue), float(m_slider->minimum()),
×
1089
                      float(m_slider->maximum()), float(0), float(200));
1090
        if (uchar(f) != 0)
×
1091
        {
1092
            QColor modColor = m_cngRGBvalue.lighter(uchar(f));
×
1093
            c = modColor.cyan();
×
1094
            m = modColor.magenta();
×
1095
            y = modColor.yellow();
×
1096
        }
1097
    }
1098

1099
    if (m_levelValueChanged)
×
1100
    {
1101
        QListIterator <LevelChannel> it(m_levelChannels);
×
1102
        while (it.hasNext() == true)
×
1103
        {
1104
            LevelChannel lch(it.next());
×
1105
            Fixture *fxi = m_doc->fixture(lch.fixture);
×
1106
            if (fxi == NULL)
×
1107
                continue;
×
1108

1109
            quint32 universe = fxi->universe();
×
1110

1111
            QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
×
1112
            if (fader.isNull())
×
1113
            {
1114
                fader = universes[universe]->requestFader(m_monitorEnabled ? Universe::Override : Universe::Auto);
×
1115
                fader->adjustIntensity(intensity());
×
1116
                m_fadersMap[universe] = fader;
×
1117
                if (m_monitorEnabled)
×
1118
                {
1119
                    qDebug() << "VC slider monitor enabled";
×
1120
                    fader->setMonitoring(true);
×
1121
                    connect(fader.data(), SIGNAL(preWriteData(quint32,QByteArray)),
×
1122
                            this, SLOT(slotUniverseWritten(quint32,QByteArray)));
1123
                }
1124
            }
1125

1126
            FadeChannel *fc = fader->getChannelFader(m_doc, universes[universe], lch.fixture, lch.channel);
×
1127
            if (fc->universe() == Universe::invalid())
×
1128
            {
1129
                fader->remove(fc);
×
1130
                continue;
×
1131
            }
1132

1133
            int chType = fc->flags();
×
1134
            const QLCChannel *qlcch = fxi->channel(lch.channel);
×
1135
            if (qlcch == NULL)
×
1136
                continue;
×
1137

1138
            // set override flag if needed
1139
            if (m_isOverriding)
×
1140
                fc->addFlag(FadeChannel::Override);
×
1141

1142
            // request to autoremove LTP channels when set
1143
            if (qlcch->group() != QLCChannel::Intensity)
×
1144
                fc->addFlag(FadeChannel::AutoRemove);
×
1145

1146
            if (chType & FadeChannel::Intensity)
×
1147
            {
1148
                if (m_cngType == ClickAndGoWidget::RGB)
×
1149
                {
1150
                    if (qlcch->colour() == QLCChannel::Red)
×
1151
                        modLevel = uchar(r);
×
1152
                    else if (qlcch->colour() == QLCChannel::Green)
×
1153
                        modLevel = uchar(g);
×
1154
                    else if (qlcch->colour() == QLCChannel::Blue)
×
1155
                        modLevel = uchar(b);
×
1156
                }
1157
                else if (m_cngType == ClickAndGoWidget::CMY)
×
1158
                {
1159
                    if (qlcch->colour() == QLCChannel::Cyan)
×
1160
                        modLevel = uchar(c);
×
1161
                    else if (qlcch->colour() == QLCChannel::Magenta)
×
1162
                        modLevel = uchar(m);
×
1163
                    else if (qlcch->colour() == QLCChannel::Yellow)
×
1164
                        modLevel = uchar(y);
×
1165
                }
1166
            }
1167

1168
            fc->setStart(fc->current());
×
1169
            fc->setTarget(modLevel);
×
1170
            fc->setReady(false);
×
1171
            fc->setElapsed(0);
×
1172

1173
            //qDebug() << "VC Slider write channel" << fc->target();
1174
        }
1175
    }
1176
    m_levelValueChanged = false;
×
1177
}
×
1178

1179
void VCSlider::writeDMXPlayback(MasterTimer* timer, QList<Universe *> ua)
×
1180
{
1181
    Q_UNUSED(ua);
1182

1183
    QMutexLocker locker(&m_playbackValueMutex);
×
1184

1185
    if (m_playbackChangeCounter == 0)
×
1186
        return;
×
1187

1188
    Function* function = m_doc->function(m_playbackFunction);
×
1189
    if (function == NULL || mode() == Doc::Design)
×
1190
        return;
×
1191

1192
    uchar value = m_playbackValue;
×
1193
    qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
1194

1195
    if (value == 0)
×
1196
    {
1197
        // Make sure we ignore the fade out time
1198
        if (function->stopped() == false)
×
1199
        {
1200
            function->stop(functionParent());
×
1201
            resetIntensityOverrideAttribute();
×
1202
        }
1203
    }
1204
    else
1205
    {
1206
        if (function->stopped() == true)
×
1207
        {
1208
#if 0 // temporarily revert #699 until a better solution is found
1209
            // Since this function is started by a fader, its fade in time
1210
            // is decided by the fader movement.
1211
            function->start(timer, functionParent(),
1212
                            0, 0, Function::defaultSpeed(), Function::defaultSpeed());
1213
#endif
1214
            function->start(timer, functionParent());
×
1215
        }
1216
        adjustFunctionIntensity(function, pIntensity * intensity());
×
1217
        emit functionStarting(m_playbackFunction, pIntensity);
×
1218
    }
1219
    m_playbackChangeCounter--;
×
1220
}
1221

1222
/*****************************************************************************
1223
 * Top label
1224
 *****************************************************************************/
1225

1226
void VCSlider::setTopLabelText(int value)
2✔
1227
{
1228
    QString text;
2✔
1229

1230
    if (valueDisplayStyle() == ExactValue)
2✔
1231
    {
1232
        text = text.asprintf("%.3d", value);
2✔
1233
    }
1234
    else
1235
    {
1236

1237
        float f = 0;
×
1238
        if (m_slider)
×
1239
            f = SCALE(float(value), float(m_slider->minimum()),
×
1240
                      float(m_slider->maximum()), float(0), float(100));
1241
        text = text.asprintf("%.3d%%", static_cast<int> (f));
×
1242
    }
1243
    m_topLabel->setText(text);
2✔
1244
    emit valueChanged(text);
2✔
1245
}
2✔
1246

1247
QString VCSlider::topLabelText()
×
1248
{
1249
    return m_topLabel->text();
×
1250
}
1251

1252
/*****************************************************************************
1253
 * Slider
1254
 *****************************************************************************/
1255

1256
void VCSlider::setSliderValue(uchar value, bool scale, bool external)
×
1257
{
1258
    if (m_slider == NULL)
×
1259
        return;
×
1260

1261
    float val = value;
×
1262

1263
    /* Scale from input value range to this slider's range */
1264
    if (scale)
×
1265
    {
1266
        val = SCALE(float(value), float(0), float(UCHAR_MAX),
×
1267
                float(m_slider->minimum()),
1268
                float(m_slider->maximum()));
1269
    }
1270

1271
    /* Request the UI to update */
1272
    if (m_slider->isSliderDown() == false && val != m_slider->value())
×
1273
       emit requestSliderUpdate(val);
×
1274

1275
    switch (sliderMode())
×
1276
    {
1277
        case Level:
×
1278
        {
1279
            if (m_monitorEnabled == true && m_isOverriding == false && m_slider->isSliderDown())
×
1280
            {
1281
                m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }"));
×
1282
                m_isOverriding = true;
×
1283
            }
1284
            setLevelValue(val, external);
×
1285
            setClickAndGoWidgetFromLevel(val);
×
1286
        }
1287
        break;
×
1288

1289
        case Playback:
×
1290
        {
1291
            setPlaybackValue(value);
×
1292
        }
1293
        break;
×
1294

1295
        case Submaster:
×
1296
        {
1297
            setLevelValue(val);
×
1298
            emitSubmasterValue();
×
1299
        }
1300
        break;
×
1301
    }
1302
}
1303

1304
void VCSlider::setSliderShadowValue(int value)
×
1305
{
1306
    if (m_widgetMode == WSlider)
×
1307
    {
1308
        ClickAndGoSlider *sl = qobject_cast<ClickAndGoSlider*> (m_slider);
×
1309
        sl->setShadowLevel(value);
×
1310
    }
1311
}
×
1312

1313
int VCSlider::sliderValue() const
×
1314
{
1315
    if (m_slider)
×
1316
        return m_slider->value();
×
1317

1318
    return 0;
×
1319
}
1320

1321
void VCSlider::setWidgetStyle(SliderWidgetStyle mode)
×
1322
{
1323
    if (mode == m_widgetMode)
×
1324
        return;
×
1325

1326
    if (mode == WKnob)
×
1327
    {
1328
        qDebug() << "Switching to knob widget";
×
1329
        disconnect(m_slider, SIGNAL(valueChanged(int)),
×
1330
                this, SLOT(slotSliderMoved(int)));
1331

1332
        QLayoutItem* item;
1333
        while ((item = m_hbox->takeAt(0)) != NULL)
×
1334
        {
1335
            delete item->widget();
×
1336
            delete item;
×
1337
        }
1338

1339
        m_slider = NULL;
×
1340

1341
        m_slider = new KnobWidget(this);
×
1342
        m_slider->setEnabled(false);
×
1343
        m_slider->setRange(levelLowLimit(), levelHighLimit());
×
1344
        m_hbox->addWidget(m_slider);
×
1345
        m_slider->show();
×
1346
        connect(m_slider, SIGNAL(valueChanged(int)),
×
1347
                this, SLOT(slotSliderMoved(int)));
1348
    }
1349
    else if (mode == WSlider)
×
1350
    {
1351
        qDebug() << "Switching to slider widget";
×
1352
        disconnect(m_slider, SIGNAL(valueChanged(int)),
×
1353
                this, SLOT(slotSliderMoved(int)));
1354

1355
        QLayoutItem* item;
1356
        while ((item = m_hbox->takeAt(0)) != NULL)
×
1357
        {
1358
            delete item->widget();
×
1359
            delete item;
×
1360
        }
1361

1362
        m_slider = NULL;
×
1363
        m_hbox->addStretch();
×
1364
        m_slider = new ClickAndGoSlider(this);
×
1365
        m_slider->setEnabled(false);
×
1366
        m_slider->setRange(levelLowLimit(), levelHighLimit());
×
1367
        m_hbox->addWidget(m_slider);
×
1368
        m_slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
×
1369
        m_slider->setMinimumWidth(32);
×
1370
        m_slider->setMaximumWidth(80);
×
1371
        m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
×
1372
        m_hbox->addStretch();
×
1373
        m_slider->show();
×
1374
        connect(m_slider, SIGNAL(valueChanged(int)),
×
1375
                this, SLOT(slotSliderMoved(int)));
1376
    }
1377
    connect(this, SIGNAL(requestSliderUpdate(int)),
×
1378
            m_slider, SLOT(setValue(int)));
×
1379
    m_widgetMode = mode;
×
1380
    update();
×
1381
}
1382

1383
VCSlider::SliderWidgetStyle VCSlider::widgetStyle() const
×
1384
{
1385
    return m_widgetMode;
×
1386
}
1387

1388
QString VCSlider::widgetStyleToString(VCSlider::SliderWidgetStyle style)
×
1389
{
1390
    if (style == VCSlider::WSlider)
×
1391
        return QString("Slider");
×
1392
    else if (style == VCSlider::WKnob)
×
1393
        return QString("Knob");
×
1394

1395
    return QString();
×
1396
}
1397

1398
VCSlider::SliderWidgetStyle VCSlider::stringToWidgetStyle(QString style)
×
1399
{
1400
    if (style == "Slider")
×
1401
        return VCSlider::WSlider;
×
1402
    else if (style == "Knob")
×
1403
        return VCSlider::WKnob;
×
1404

1405
    return VCSlider::WSlider;
×
1406
}
1407

1408
void VCSlider::updateFeedback()
×
1409
{
1410
    int fbv = 0;
×
1411
    if (m_slider)
×
1412
    {
1413
        if (invertedAppearance() == true)
×
1414
            fbv = m_slider->maximum() - m_slider->value() + m_slider->minimum();
×
1415
        else
1416
            fbv = m_slider->value();
×
1417
        fbv = int(SCALE(float(fbv), float(m_slider->minimum()),
×
1418
                        float(m_slider->maximum()), float(0), float(UCHAR_MAX)));
1419
    }
1420
    sendFeedback(fbv);
×
1421
}
×
1422

1423
void VCSlider::slotSliderMoved(int value)
2✔
1424
{
1425
    /* Set text for the top label */
1426
    setTopLabelText(value);
2✔
1427

1428
    /* Do the rest only if the slider is being moved by the user */
1429
    if (m_slider->isSliderDown() == false)
2✔
1430
        return;
2✔
1431

1432
    setSliderValue(value, false);
×
1433

1434
    updateFeedback();
×
1435
}
1436

1437
/*****************************************************************************
1438
 * Bottom label
1439
 *****************************************************************************/
1440
void VCSlider::setBottomLabelText(const QString& text)
×
1441
{
1442
    m_bottomLabel->setText(text);
×
1443
}
×
1444

1445
QString VCSlider::bottomLabelText()
×
1446
{
1447
    return m_bottomLabel->text();
×
1448
}
1449

1450
/*****************************************************************************
1451
 * External input
1452
 *****************************************************************************/
1453

1454
void VCSlider::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
1455
{
1456
    /* Don't let input data through in design mode or if disabled */
1457
    if (acceptsInput() == false)
×
1458
        return;
×
1459

1460
    quint32 pagedCh = (page() << 16) | channel;
×
1461

1462
    if (checkInputSource(universe, pagedCh, value, sender(), sliderInputSourceId))
×
1463
    {
1464
        if (m_slider)
×
1465
        {
1466
            /* When 'values catching" is enabled, controllers that do not have motorized faders
1467
             * can catch up with the current slider value by entering a certain threshold
1468
             * or by 'surpassing' the current value */
1469
            if (catchValues())
×
1470
            {
1471
                uchar currentValue = sliderValue();
×
1472

1473
                // filter 'out of threshold' cases
1474
                if (m_lastInputValue == -1 ||
×
1475
                    (m_lastInputValue < currentValue - VALUE_CATCHING_THRESHOLD && value < currentValue - VALUE_CATCHING_THRESHOLD) ||
×
1476
                    (m_lastInputValue > currentValue + VALUE_CATCHING_THRESHOLD && value > currentValue + VALUE_CATCHING_THRESHOLD))
×
1477
                {
1478
                    m_lastInputValue = value;
×
1479
                    return;
×
1480
                }
1481
            }
1482

1483
            if (m_monitorEnabled == true && m_isOverriding == false)
×
1484
            {
1485
                m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }"));
×
1486
                m_isOverriding = true;
×
1487
            }
1488

1489
            if (invertedAppearance())
×
1490
                value = UCHAR_MAX - value;
×
1491

1492
            setSliderValue(value, true, true);
×
1493
            m_lastInputValue = value;
×
1494
        }
1495
    }
1496
    else if (checkInputSource(universe, pagedCh, value, sender(), overrideResetInputSourceId))
×
1497
    {
1498
        if (value > 0)
×
1499
            slotResetButtonClicked();
×
1500
    }
1501
}
1502

1503
void VCSlider::adjustIntensity(qreal val)
×
1504
{
1505
    VCWidget::adjustIntensity(val);
×
1506

1507
    if (sliderMode() == Playback)
×
1508
    {
1509
        Function* function = m_doc->function(m_playbackFunction);
×
1510
        if (function == NULL || mode() == Doc::Design)
×
1511
            return;
×
1512

1513
        qreal pIntensity = qreal(m_playbackValue) / qreal(UCHAR_MAX);
×
1514
        adjustFunctionIntensity(function, pIntensity * intensity());
×
1515
    }
1516
    else if (sliderMode() == Level)
×
1517
    {
1518
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
1519
        {
1520
            if (!fader.isNull())
×
1521
                fader->adjustIntensity(val);
×
1522
        }
1523
    }
1524
}
1525

1526
/*****************************************************************************
1527
 * Load & Save
1528
 *****************************************************************************/
1529

1530
bool VCSlider::loadXML(QXmlStreamReader &root)
1✔
1531
{
1532
    bool visible = false;
1✔
1533
    int x = 0;
1✔
1534
    int y = 0;
1✔
1535
    int w = 0;
1✔
1536
    int h = 0;
1✔
1537

1538
    SliderMode sliderMode = Playback;
1✔
1539
    QString str;
2✔
1540

1541
    if (root.name() != KXMLQLCVCSlider)
1✔
1542
    {
1543
        qWarning() << Q_FUNC_INFO << "Slider node not found";
×
1544
        return false;
×
1545
    }
1546

1547
    /* Widget commons */
1548
    loadXMLCommon(root);
1✔
1549

1550
    QXmlStreamAttributes attrs = root.attributes();
1✔
1551

1552
    /* Widget style */
1553
    if (attrs.hasAttribute(KXMLQLCVCSliderWidgetStyle))
1✔
1554
        setWidgetStyle(stringToWidgetStyle(attrs.value(KXMLQLCVCSliderWidgetStyle).toString()));
×
1555

1556
    if (attrs.value(KXMLQLCVCSliderInvertedAppearance).toString() == "false")
1✔
1557
        setInvertedAppearance(false);
×
1558
    else
1559
        setInvertedAppearance(true);
1✔
1560

1561
    /* Values catching */
1562
    if (attrs.hasAttribute(KXMLQLCVCSliderCatchValues))
1✔
1563
        setCatchValues(true);
×
1564

1565
    /* Children */
1566
    while (root.readNextStartElement())
1✔
1567
    {
1568
        //qDebug() << "VC Slider tag:" << root.name();
1569
        if (root.name() == KXMLQLCWindowState)
×
1570
        {
1571
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
×
1572
            setGeometry(x, y, w, h);
×
1573
        }
1574
        else if (root.name() == KXMLQLCVCWidgetAppearance)
×
1575
        {
1576
            loadXMLAppearance(root);
×
1577
        }
1578
        else if (root.name() == KXMLQLCVCSliderMode)
×
1579
        {
1580
            QXmlStreamAttributes mAttrs = root.attributes();
×
1581
            sliderMode = stringToSliderMode(root.readElementText());
×
1582

1583
            str = mAttrs.value(KXMLQLCVCSliderValueDisplayStyle).toString();
×
1584
            setValueDisplayStyle(stringToValueDisplayStyle(str));
×
1585

1586
            if (mAttrs.hasAttribute(KXMLQLCVCSliderClickAndGoType))
×
1587
            {
1588
                str = mAttrs.value(KXMLQLCVCSliderClickAndGoType).toString();
×
1589
                setClickAndGoType(ClickAndGoWidget::stringToClickAndGoType(str));
×
1590
            }
1591

1592
            if (mAttrs.hasAttribute(KXMLQLCVCSliderLevelMonitor))
×
1593
            {
1594
                if (mAttrs.value(KXMLQLCVCSliderLevelMonitor).toString() == "false")
×
1595
                    setChannelsMonitorEnabled(false);
×
1596
                else
1597
                    setChannelsMonitorEnabled(true);
×
1598
            }
1599
        }
1600
        else if (root.name() == KXMLQLCVCSliderOverrideReset)
×
1601
        {
1602
            QString str = loadXMLSources(root, overrideResetInputSourceId);
×
1603
            if (str.isEmpty() == false)
×
1604
                m_overrideResetKeySequence = stripKeySequence(QKeySequence(str));
×
1605
        }
1606
        else if (root.name() == KXMLQLCVCSliderLevel)
×
1607
        {
1608
            loadXMLLevel(root);
×
1609
        }
1610
        else if (root.name() == KXMLQLCVCWidgetInput)
×
1611
        {
1612
            loadXMLInput(root);
×
1613
        }
1614
        else if (root.name() == KXMLQLCVCSliderPlayback)
×
1615
        {
1616
            loadXMLPlayback(root);
×
1617
        }
1618
        else
1619
        {
1620
            qWarning() << Q_FUNC_INFO << "Unknown slider tag:" << root.name().toString();
×
1621
            root.skipCurrentElement();
×
1622
        }
1623
    }
1624

1625
    /* Set the mode last, after everything else has been set */
1626
    setSliderMode(sliderMode);
1✔
1627

1628
    return true;
1✔
1629
}
1630

1631
bool VCSlider::loadXMLLevel(QXmlStreamReader &level_root)
×
1632
{
1633
    QString str;
×
1634

1635
    if (level_root.name() != KXMLQLCVCSliderLevel)
×
1636
    {
1637
        qWarning() << Q_FUNC_INFO << "Slider level node not found";
×
1638
        return false;
×
1639
    }
1640

1641
    QXmlStreamAttributes attrs = level_root.attributes();
×
1642

1643
    /* Level low limit */
1644
    str = attrs.value(KXMLQLCVCSliderLevelLowLimit).toString();
×
1645
    setLevelLowLimit(str.toInt());
×
1646

1647
    /* Level high limit */
1648
    str = attrs.value(KXMLQLCVCSliderLevelHighLimit).toString();
×
1649
    setLevelHighLimit(str.toInt());
×
1650

1651
    /* Level value */
1652
    str = attrs.value(KXMLQLCVCSliderLevelValue).toString();
×
1653
    setLevelValue(str.toInt());
×
1654

1655
    QXmlStreamReader::TokenType tType = level_root.readNext();
×
1656

1657
    if (tType == QXmlStreamReader::EndElement)
×
1658
    {
1659
        level_root.readNext();
×
1660
        return true;
×
1661
    }
1662

1663
    if (tType == QXmlStreamReader::Characters)
×
1664
        tType = level_root.readNext();
×
1665

1666
    // check if there is a Channel tag defined
1667
    if (tType == QXmlStreamReader::StartElement)
×
1668
    {
1669
        /* Children */
1670
        do
×
1671
        {
1672
            if (level_root.name() == KXMLQLCVCSliderChannel)
×
1673
            {
1674
                /* Fixture & channel */
1675
                str = level_root.attributes().value(KXMLQLCVCSliderChannelFixture).toString();
×
1676
                addLevelChannel(
×
1677
                    static_cast<quint32>(str.toInt()),
×
1678
                    static_cast<quint32> (level_root.readElementText().toInt()));
×
1679
            }
1680
            else
1681
            {
1682
                qWarning() << Q_FUNC_INFO << "Unknown slider level tag:" << level_root.name().toString();
×
1683
                level_root.skipCurrentElement();
×
1684
            }
1685
        } while (level_root.readNextStartElement());
×
1686
    }
1687

1688
    return true;
×
1689
}
1690

1691
bool VCSlider::loadXMLPlayback(QXmlStreamReader &pb_root)
×
1692
{
1693
    if (pb_root.name() != KXMLQLCVCSliderPlayback)
×
1694
    {
1695
        qWarning() << Q_FUNC_INFO << "Slider playback node not found";
×
1696
        return false;
×
1697
    }
1698

1699
    /* Children */
1700
    while (pb_root.readNextStartElement())
×
1701
    {
1702
        if (pb_root.name() == KXMLQLCVCSliderPlaybackFunction)
×
1703
        {
1704
            /* Function */
1705
            setPlaybackFunction(pb_root.readElementText().toUInt());
×
1706
        }
1707
        else
1708
        {
1709
            qWarning() << Q_FUNC_INFO << "Unknown slider playback tag:" << pb_root.name().toString();
×
1710
            pb_root.skipCurrentElement();
×
1711
        }
1712
    }
1713

1714
    return true;
×
1715
}
1716

1717
bool VCSlider::saveXML(QXmlStreamWriter *doc)
×
1718
{
1719
    QString str;
×
1720

1721
    Q_ASSERT(doc != NULL);
×
1722

1723
    /* VC Slider entry */
1724
    doc->writeStartElement(KXMLQLCVCSlider);
×
1725

1726
    saveXMLCommon(doc);
×
1727

1728
    /* Widget style */
1729
    doc->writeAttribute(KXMLQLCVCSliderWidgetStyle, widgetStyleToString(widgetStyle()));
×
1730

1731
    /* Inverted appearance */
1732
    if (invertedAppearance() == true)
×
1733
        doc->writeAttribute(KXMLQLCVCSliderInvertedAppearance, "true");
×
1734
    else
1735
        doc->writeAttribute(KXMLQLCVCSliderInvertedAppearance, "false");
×
1736

1737
    /* Values catching */
1738
    if (catchValues() == true)
×
1739
        doc->writeAttribute(KXMLQLCVCSliderCatchValues, "true");
×
1740

1741
    /* Window state */
1742
    saveXMLWindowState(doc);
×
1743

1744
    /* Appearance */
1745
    saveXMLAppearance(doc);
×
1746

1747
    /* External input */
1748
    saveXMLInput(doc, inputSource(sliderInputSourceId));
×
1749

1750
    /* SliderMode */
1751
    doc->writeStartElement(KXMLQLCVCSliderMode);
×
1752

1753
    /* Value display style */
1754
    str = valueDisplayStyleToString(valueDisplayStyle());
×
1755
    doc->writeAttribute(KXMLQLCVCSliderValueDisplayStyle, str);
×
1756

1757
    /* Click And Go type */
1758
    str = ClickAndGoWidget::clickAndGoTypeToString(m_cngType);
×
1759
    doc->writeAttribute(KXMLQLCVCSliderClickAndGoType, str);
×
1760

1761
    /* Monitor channels */
1762
    if (sliderMode() == Level)
×
1763
    {
1764
        if (channelsMonitorEnabled() == true)
×
1765
            doc->writeAttribute(KXMLQLCVCSliderLevelMonitor, "true");
×
1766
        else
1767
            doc->writeAttribute(KXMLQLCVCSliderLevelMonitor, "false");
×
1768
    }
1769

1770
    doc->writeCharacters(sliderModeToString(m_sliderMode));
×
1771

1772
    /* End the <SliderMode> tag */
1773
    doc->writeEndElement();
×
1774

1775
    if (sliderMode() == Level && channelsMonitorEnabled() == true)
×
1776
    {
1777
        doc->writeStartElement(KXMLQLCVCSliderOverrideReset);
×
1778
        if (m_overrideResetKeySequence.toString().isEmpty() == false)
×
1779
            doc->writeTextElement(KXMLQLCVCWidgetKey, m_overrideResetKeySequence.toString());
×
1780
        saveXMLInput(doc, inputSource(overrideResetInputSourceId));
×
1781
        doc->writeEndElement();
×
1782
    }
1783

1784
    /* Level */
1785
    doc->writeStartElement(KXMLQLCVCSliderLevel);
×
1786
    /* Level low limit */
1787
    doc->writeAttribute(KXMLQLCVCSliderLevelLowLimit, QString::number(levelLowLimit()));
×
1788
    /* Level high limit */
1789
    doc->writeAttribute(KXMLQLCVCSliderLevelHighLimit, QString::number(levelHighLimit()));
×
1790
    /* Level value */
1791
    doc->writeAttribute(KXMLQLCVCSliderLevelValue, QString::number(levelValue()));
×
1792

1793
    /* Level channels */
1794
    QListIterator <LevelChannel> it(m_levelChannels);
×
1795
    while (it.hasNext() == true)
×
1796
    {
1797
        LevelChannel lch(it.next());
×
1798
        lch.saveXML(doc);
×
1799
    }
1800

1801
    /* End the <Level> tag */
1802
    doc->writeEndElement();
×
1803

1804
    /* Playback */
1805
    doc->writeStartElement(KXMLQLCVCSliderPlayback);
×
1806
    /* Playback function */
1807
    doc->writeTextElement(KXMLQLCVCSliderPlaybackFunction, QString::number(playbackFunction()));
×
1808
    /* End the <Playback> tag */
1809
    doc->writeEndElement();
×
1810

1811
    /* End the <Slider> tag */
1812
    doc->writeEndElement();
×
1813

1814
    return true;
×
1815
}
1816

1817
/****************************************************************************
1818
 * LevelChannel implementation
1819
 ****************************************************************************/
1820

1821
VCSlider::LevelChannel::LevelChannel(quint32 fid, quint32 ch)
×
1822
{
1823
    this->fixture = fid;
×
1824
    this->channel = ch;
×
1825
}
×
1826

1827
VCSlider::LevelChannel::LevelChannel(const LevelChannel& lc)
×
1828
{
1829
    *this = lc;
×
1830
}
×
1831

1832
VCSlider::LevelChannel &VCSlider::LevelChannel::operator=(const VCSlider::LevelChannel &lc)
×
1833
{
1834
    if (this != &lc)
×
1835
    {
1836
        this->fixture = lc.fixture;
×
1837
        this->channel = lc.channel;
×
1838
    }
1839

1840
    return *this;
×
1841
}
1842

1843
bool VCSlider::LevelChannel::operator==(const LevelChannel& lc) const
×
1844
{
1845
    return (this->fixture == lc.fixture && this->channel == lc.channel);
×
1846
}
1847

1848
bool VCSlider::LevelChannel::operator<(const LevelChannel& lc) const
×
1849
{
1850
    if (this->fixture < lc.fixture)
×
1851
        return true;
×
1852
    else if (this->fixture == lc.fixture && this->channel < lc.channel)
×
1853
        return true;
×
1854
    else
1855
        return false;
×
1856
}
1857

1858
void VCSlider::LevelChannel::saveXML(QXmlStreamWriter *doc) const
×
1859
{
1860
    Q_ASSERT(doc != NULL);
×
1861

1862
    doc->writeStartElement(KXMLQLCVCSliderChannel);
×
1863

1864
    doc->writeAttribute(KXMLQLCVCSliderChannelFixture,
×
1865
                       QString::number(this->fixture));
×
1866

1867
    doc->writeCharacters(QString::number(this->channel));
×
1868
    doc->writeEndElement();
×
1869
}
×
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