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

mcallegari / qlcplus / 6683238402

29 Oct 2023 12:10PM UTC coverage: 28.07%. Remained the same
6683238402

push

github

mcallegari
engine: fix build

15385 of 54809 relevant lines covered (28.07%)

20267.63 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 "genericfader.h"
44
#include "fadechannel.h"
45
#include "mastertimer.h"
46
#include "qlcmacros.h"
47
#include "universe.h"
48
#include "vcslider.h"
49
#include "apputil.h"
50
#include "doc.h"
51

52
/** Number of DMXSource cycles to wait to consider a
53
 *  playback value change stable */
54
#define PLAYBACK_CHANGE_THRESHOLD   5  // roughly this is 100ms
55

56
/** +/- value range to catch the slider for external
57
 *  controllers with no feedback support */
58
#define VALUE_CATCHING_THRESHOLD    4
59

60
const quint8 VCSlider::sliderInputSourceId = 0;
61
const quint8 VCSlider::overrideResetInputSourceId = 1;
62

63
const QSize VCSlider::defaultSize(QSize(60, 200));
64

65
const QString submasterStyleSheet =
66
    SLIDER_SS_COMMON
67

68
    "QSlider::handle:vertical { "
69
    "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);"
70
    "border: 1px solid #5c5c5c;"
71
    "border-radius: 4px; margin: 0 -4px; height: 20px; }"
72

73
    "QSlider::handle:vertical:hover {"
74
    "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);"
75
    "border: 1px solid #000; }"
76

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

80
/*****************************************************************************
81
 * Initialization
82
 *****************************************************************************/
83

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

106
    m_hbox = NULL;
1✔
107
    m_topLabel = NULL;
1✔
108
    m_slider = NULL;
1✔
109
    m_bottomLabel = NULL;
1✔
110

111
    setType(VCWidget::SliderWidget);
1✔
112
    setCaption(QString());
1✔
113
    setFrameStyle(KVCFrameStyleSunken);
1✔
114

115
    /* Main VBox */
116
    new QVBoxLayout(this);
1✔
117

118
    /* Top label */
119
    m_topLabel = new QLabel(this);
1✔
120
    m_topLabel->setAlignment(Qt::AlignHCenter);
1✔
121

122
    layout()->addWidget(m_topLabel);
1✔
123

124
    /* Slider's HBox |stretch|slider|stretch| */
125
    m_hbox = new QHBoxLayout();
1✔
126

127
    /* Put stretchable space before the slider (to its left side) */
128
    m_hbox->addStretch();
1✔
129

130
    /* The slider */
131
    m_slider = new ClickAndGoSlider(this);
1✔
132

133
    m_hbox->addWidget(m_slider);
1✔
134
    m_slider->setRange(0, 255);
1✔
135
    m_slider->setPageStep(1);
1✔
136
    m_slider->setInvertedAppearance(false);
1✔
137
    m_slider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
1✔
138
    m_slider->setMinimumWidth(32);
1✔
139
    m_slider->setMaximumWidth(80);
1✔
140
    m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
1✔
141

142
    connect(m_slider, SIGNAL(valueChanged(int)),
1✔
143
            this, SLOT(slotSliderMoved(int)));
144
    connect(this, SIGNAL(requestSliderUpdate(int)),
2✔
145
            m_slider, SLOT(setValue(int)));
1✔
146

147
    /* Put stretchable space after the slider (to its right side) */
148
    m_hbox->addStretch();
1✔
149

150
    layout()->addItem(m_hbox);
1✔
151

152
    /* Click & Go button */
153
    m_cngButton = new QToolButton(this);
1✔
154
    m_cngButton->setFixedSize(48, 48);
1✔
155
    m_cngButton->setIconSize(QSize(42, 42));
1✔
156
    m_menu = new QMenu(this);
1✔
157
    QWidgetAction* action = new QWidgetAction(this);
1✔
158
    m_cngWidget = new ClickAndGoWidget();
1✔
159
    action->setDefaultWidget(m_cngWidget);
1✔
160
    m_menu->addAction(action);
1✔
161
    m_cngButton->setMenu(m_menu);
1✔
162
    m_cngButton->setPopupMode(QToolButton::InstantPopup);
1✔
163
    layout()->addWidget(m_cngButton);
1✔
164
    layout()->setAlignment(m_cngButton, Qt::AlignHCenter);
1✔
165
    m_cngButton->hide();
1✔
166

167
    connect(m_cngWidget, SIGNAL(levelChanged(uchar)),
1✔
168
            this, SLOT(slotClickAndGoLevelChanged(uchar)));
169
    connect(m_cngWidget, SIGNAL(colorChanged(QRgb)),
1✔
170
            this, SLOT(slotClickAndGoColorChanged(QRgb)));
171
    connect(m_cngWidget, SIGNAL(levelAndPresetChanged(uchar,QImage)),
1✔
172
            this, SLOT(slotClickAndGoLevelAndPresetChanged(uchar, QImage)));
173
    connect(this, SIGNAL(monitorDMXValueChanged(int)),
1✔
174
            this, SLOT(slotMonitorDMXValueChanged(int)));
175

176
    m_resetButton = NULL;
1✔
177

178
    /* Bottom label */
179
    m_bottomLabel = new QLabel(this);
1✔
180
    layout()->addWidget(m_bottomLabel);
1✔
181
    m_bottomLabel->setAlignment(Qt::AlignCenter);
1✔
182
    m_bottomLabel->setWordWrap(true);
1✔
183
    m_bottomLabel->hide();
1✔
184

185
    setMinimumSize(20, 20);
1✔
186
    QSettings settings;
2✔
187
    QVariant var = settings.value(SETTINGS_SLIDER_SIZE);
2✔
188
    if (var.isValid() == true)
1✔
189
        resize(var.toSize());
×
190
    else
191
        resize(VCSlider::defaultSize);
1✔
192

193
    /* Initialize to playback mode by default */
194
    setInvertedAppearance(false);
1✔
195
    m_sliderMode = SliderMode(-1); // avoid use of uninitialized value
1✔
196
    setSliderMode(Playback);
1✔
197

198
    /* Update the slider according to current mode */
199
    slotModeChanged(m_doc->mode());
1✔
200
    setLiveEdit(m_liveEdit);
1✔
201

202
    /* Listen to fixture removals so that LevelChannels can be removed when
203
       they no longer point to an existing fixture->channel */
204
    connect(m_doc, SIGNAL(fixtureRemoved(quint32)),
1✔
205
            this, SLOT(slotFixtureRemoved(quint32)));
206
}
1✔
207

208
VCSlider::~VCSlider()
2✔
209
{
210
    /* When application exits these are already NULL and unregistration
211
       is no longer necessary. But a normal deletion of a VCSlider in
212
       design mode must unregister the slider. */
213
    m_doc->masterTimer()->unregisterDMXSource(this);
1✔
214

215
    // request to delete all the active faders
216
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
2✔
217
    {
218
        if (!fader.isNull())
×
219
            fader->requestDelete();
×
220
    }
221
    m_fadersMap.clear();
1✔
222
}
2✔
223

224
void VCSlider::setID(quint32 id)
×
225
{
226
    VCWidget::setID(id);
×
227

228
    if (caption().isEmpty())
×
229
        setCaption(tr("Slider %1").arg(id));
×
230
}
×
231

232
/*****************************************************************************
233
 * Clipboard
234
 *****************************************************************************/
235

236
VCWidget* VCSlider::createCopy(VCWidget* parent)
×
237
{
238
    Q_ASSERT(parent != NULL);
×
239

240
    VCSlider* slider = new VCSlider(parent, m_doc);
×
241
    if (slider->copyFrom(this) == false)
×
242
    {
243
        delete slider;
×
244
        slider = NULL;
×
245
    }
246

247
    return slider;
×
248
}
249

250
bool VCSlider::copyFrom(const VCWidget* widget)
×
251
{
252
    const VCSlider* slider = qobject_cast<const VCSlider*> (widget);
×
253
    if (slider == NULL)
×
254
        return false;
×
255

256
    /* Copy widget style */
257
    setWidgetStyle(slider->widgetStyle());
×
258

259
    /* Copy level stuff */
260
    setLevelLowLimit(slider->levelLowLimit());
×
261
    setLevelHighLimit(slider->levelHighLimit());
×
262
    m_levelChannels = slider->m_levelChannels;
×
263

264
    /* Copy playback stuff */
265
    m_playbackFunction = slider->m_playbackFunction;
×
266

267
    /* Copy slider appearance */
268
    setValueDisplayStyle(slider->valueDisplayStyle());
×
269
    setInvertedAppearance(slider->invertedAppearance());
×
270

271
    /* Copy Click & Go feature */
272
    setClickAndGoType(slider->clickAndGoType());
×
273

274
    /* Copy mode & current value */
275
    setSliderMode(slider->sliderMode());
×
276
    setSliderValue(slider->sliderValue());
×
277

278
    /* Copy monitor mode */
279
    setChannelsMonitorEnabled(slider->channelsMonitorEnabled());
×
280

281
    /* Copy common stuff */
282
    return VCWidget::copyFrom(widget);
×
283
}
284

285
/*****************************************************************************
286
 * GUI
287
 *****************************************************************************/
288

289
void VCSlider::setCaption(const QString& text)
1✔
290
{
291
    VCWidget::setCaption(text);
1✔
292

293
    if (m_bottomLabel != NULL)
1✔
294
        setBottomLabelText(text);
×
295
}
1✔
296

297
void VCSlider::enableWidgetUI(bool enable)
1✔
298
{
299
    m_topLabel->setEnabled(enable);
1✔
300
    if (m_slider)
1✔
301
        m_slider->setEnabled(enable);
1✔
302
    m_bottomLabel->setEnabled(enable);
1✔
303
    m_cngButton->setEnabled(enable);
1✔
304
    if (m_resetButton)
1✔
305
        m_resetButton->setEnabled(enable);
×
306
    if (enable == false)
1✔
307
        m_lastInputValue = -1;
1✔
308
}
1✔
309

310
void VCSlider::hideEvent(QHideEvent *)
×
311
{
312
    m_lastInputValue = -1;
×
313
}
×
314

315
/*****************************************************************************
316
 * Properties
317
 *****************************************************************************/
318

319
void VCSlider::editProperties()
×
320
{
321
    VCSliderProperties prop(this, m_doc);
×
322
    if (prop.exec() == QDialog::Accepted)
×
323
    {
324
        m_doc->setModified();
×
325
        if (m_cngType == ClickAndGoWidget::None)
×
326
            m_cngButton->hide();
×
327
        else
328
            m_cngButton->show();
×
329
    }
330
}
×
331

332
/*****************************************************************************
333
 * QLC Mode
334
 *****************************************************************************/
335

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

364
    VCWidget::slotModeChanged(mode);
1✔
365
}
1✔
366

367
/*****************************************************************************
368
 * Value display style
369
 *****************************************************************************/
370

371
QString VCSlider::valueDisplayStyleToString(VCSlider::ValueDisplayStyle style)
×
372
{
373
    switch (style)
×
374
    {
375
    case ExactValue:
×
376
        return KXMLQLCVCSliderValueDisplayStyleExact;
×
377
    case PercentageValue:
×
378
        return KXMLQLCVCSliderValueDisplayStylePercentage;
×
379
    default:
×
380
        return QString("Unknown");
×
381
    };
382
}
383

384
VCSlider::ValueDisplayStyle VCSlider::stringToValueDisplayStyle(QString style)
×
385
{
386
    if (style == KXMLQLCVCSliderValueDisplayStyleExact)
×
387
        return ExactValue;
×
388
    else if (style == KXMLQLCVCSliderValueDisplayStylePercentage)
×
389
        return PercentageValue;
×
390
    else
391
        return ExactValue;
×
392
}
393

394
void VCSlider::setValueDisplayStyle(VCSlider::ValueDisplayStyle style)
×
395
{
396
    m_valueDisplayStyle = style;
×
397
    if (m_slider)
×
398
        setTopLabelText(m_slider->value());
×
399
}
×
400

401
VCSlider::ValueDisplayStyle VCSlider::valueDisplayStyle() const
2✔
402
{
403
    return m_valueDisplayStyle;
2✔
404
}
405

406
/*****************************************************************************
407
 * Inverted appearance
408
 *****************************************************************************/
409

410
bool VCSlider::invertedAppearance() const
×
411
{
412
    if (m_slider)
×
413
        return m_slider->invertedAppearance();
×
414

415
    return false;
×
416
}
417

418
void VCSlider::setInvertedAppearance(bool invert)
2✔
419
{
420
    if (m_slider)
2✔
421
    {
422
        m_slider->setInvertedAppearance(invert);
2✔
423
        m_slider->setInvertedControls(invert);
2✔
424
    }
425
}
2✔
426

427
/*********************************************************************
428
 * Value catching feature
429
 *********************************************************************/
430

431
bool VCSlider::catchValues() const
×
432
{
433
    return m_catchValues;
×
434
}
435

436
void VCSlider::setCatchValues(bool enable)
×
437
{
438
    if (enable == m_catchValues)
×
439
        return;
×
440

441
    m_catchValues = enable;
×
442
}
443

444
/*****************************************************************************
445
 * Slider Mode
446
 *****************************************************************************/
447

448
QString VCSlider::sliderModeToString(SliderMode mode)
×
449
{
450
    switch (mode)
×
451
    {
452
        case Level: return QString("Level"); break;
×
453
        case Playback: return QString("Playback"); break;
×
454
        case Submaster: return QString("Submaster"); break;
×
455
        default: return QString("Unknown"); break;
×
456
    }
457
}
458

459
VCSlider::SliderMode VCSlider::stringToSliderMode(const QString& mode)
×
460
{
461
    if (mode == QString("Level"))
×
462
        return Level;
×
463
    else  if (mode == QString("Playback"))
×
464
       return Playback;
×
465
    else //if (mode == QString("Submaster"))
466
        return Submaster;
×
467
}
468

469
VCSlider::SliderMode VCSlider::sliderMode() const
×
470
{
471
    return m_sliderMode;
×
472
}
473

474
void VCSlider::setSliderMode(SliderMode mode)
2✔
475
{
476
    Q_ASSERT(mode >= Level && mode <= Submaster);
2✔
477

478
    m_sliderMode = mode;
2✔
479

480
    if (mode == Level)
2✔
481
    {
482
        /* Set the slider range */
483
        if (m_slider)
×
484
        {
485
            m_slider->setRange(levelLowLimit(), levelHighLimit());
×
486
            m_slider->setValue(levelValue());
×
487
            if (m_widgetMode == WSlider)
×
488
                m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
×
489
        }
490

491
        m_bottomLabel->show();
×
492
        if (m_cngType != ClickAndGoWidget::None)
×
493
        {
494
            setClickAndGoType(m_cngType);
×
495
            setupClickAndGoWidget();
×
496
            m_cngButton->show();
×
497
            if (m_slider)
×
498
                setClickAndGoWidgetFromLevel(m_slider->value());
×
499
        }
500

501
        if (m_doc->mode() == Doc::Operate)
×
502
            m_doc->masterTimer()->registerDMXSource(this);
×
503
    }
504
    else if (mode == Playback)
2✔
505
    {
506
        m_bottomLabel->show();
2✔
507
        m_cngButton->hide();
2✔
508
        m_monitorEnabled = false;
2✔
509

510
        uchar level = playbackValue();
2✔
511
        if (m_slider)
2✔
512
        {
513
            m_slider->setRange(0, UCHAR_MAX);
2✔
514
            m_slider->setValue(level);
2✔
515
            if (m_widgetMode == WSlider)
2✔
516
                m_slider->setStyleSheet(CNG_DEFAULT_STYLE);
2✔
517
        }
518
        slotSliderMoved(level);
2✔
519

520
        if (m_doc->mode() == Doc::Operate)
2✔
521
            m_doc->masterTimer()->registerDMXSource(this);
×
522
        setPlaybackFunction(this->m_playbackFunction);
2✔
523
    }
524
    else if (mode == Submaster)
×
525
    {
526
        m_monitorEnabled = false;
×
527
        setPlaybackFunction(Function::invalidId());
×
528

529
        if (m_slider)
×
530
        {
531
            m_slider->setRange(0, UCHAR_MAX);
×
532
            m_slider->setValue(levelValue());
×
533
            if (m_widgetMode == WSlider)
×
534
                m_slider->setStyleSheet(submasterStyleSheet);
×
535
        }
536
        if (m_doc->mode() == Doc::Operate)
×
537
            m_doc->masterTimer()->unregisterDMXSource(this);
×
538
    }
539
}
2✔
540

541
/*****************************************************************************
542
 * Level
543
 *****************************************************************************/
544

545
void VCSlider::addLevelChannel(quint32 fixture, quint32 channel)
×
546
{
547
    LevelChannel lch(fixture, channel);
×
548

549
    if (m_levelChannels.contains(lch) == false)
×
550
    {
551
        m_levelChannels.append(lch);
×
552
        std::sort(m_levelChannels.begin(), m_levelChannels.end());
×
553
    }
554
}
×
555

556
void VCSlider::removeLevelChannel(quint32 fixture, quint32 channel)
×
557
{
558
    LevelChannel lch(fixture, channel);
×
559
    m_levelChannels.removeAll(lch);
×
560
}
×
561

562
void VCSlider::clearLevelChannels()
×
563
{
564
    m_levelChannels.clear();
×
565
}
×
566

567
QList <VCSlider::LevelChannel> VCSlider::levelChannels()
×
568
{
569
    return m_levelChannels;
×
570
}
571

572
void VCSlider::setLevelLowLimit(uchar value)
×
573
{
574
    m_levelLowLimit = value;
×
575
}
×
576

577
uchar VCSlider::levelLowLimit() const
×
578
{
579
    return m_levelLowLimit;
×
580
}
581

582
void VCSlider::setLevelHighLimit(uchar value)
×
583
{
584
    m_levelHighLimit = value;
×
585
}
×
586

587
uchar VCSlider::levelHighLimit() const
×
588
{
589
    return m_levelHighLimit;
×
590
}
591

592
void VCSlider::setChannelsMonitorEnabled(bool enable)
×
593
{
594
    m_monitorEnabled = enable;
×
595

596
    if (m_resetButton != NULL)
×
597
    {
598
        disconnect(m_resetButton, SIGNAL(clicked(bool)),
×
599
                this, SLOT(slotResetButtonClicked()));
600
        delete m_resetButton;
×
601
        m_resetButton = NULL;
×
602
    }
603

604
    if (enable)
×
605
    {
606
        m_resetButton = new QToolButton(this);
×
607
        m_cngButton->setFixedSize(32, 32);
×
608
        m_resetButton->setIconSize(QSize(32, 32));
×
609
        m_resetButton->setStyle(AppUtil::saneStyle());
×
610
        m_resetButton->setIcon(QIcon(":/fileclose.png"));
×
611
        m_resetButton->setToolTip(tr("Reset channels override"));
×
612
        layout()->addWidget(m_resetButton);
×
613
        layout()->setAlignment(m_resetButton, Qt::AlignHCenter);
×
614

615
        connect(m_resetButton, SIGNAL(clicked(bool)),
×
616
                this, SLOT(slotResetButtonClicked()));
617
        m_resetButton->show();
×
618
        setSliderShadowValue(m_monitorValue);
×
619
    }
620
    else
621
    {
622
        setSliderShadowValue(-1);
×
623
    }
624
}
×
625

626
bool VCSlider::channelsMonitorEnabled() const
×
627
{
628
    return m_monitorEnabled;
×
629
}
630

631
void VCSlider::setLevelValue(uchar value, bool external)
×
632
{
633
    QMutexLocker locker(&m_levelValueMutex);
×
634
    m_levelValue = CLAMP(value, levelLowLimit(), levelHighLimit());
×
635
    if (m_monitorEnabled == true)
×
636
        m_monitorValue = m_levelValue;
×
637
    if (m_slider->isSliderDown() || external)
×
638
        m_levelValueChanged = true;
×
639
}
×
640

641
uchar VCSlider::levelValue() const
×
642
{
643
    return m_levelValue;
×
644
}
645

646
void VCSlider::slotFixtureRemoved(quint32 fxi_id)
×
647
{
648
    QMutableListIterator <LevelChannel> it(m_levelChannels);
×
649
    while (it.hasNext() == true)
×
650
    {
651
        it.next();
×
652
        if (it.value().fixture == fxi_id)
×
653
            it.remove();
×
654
    }
655
}
×
656

657
void VCSlider::slotMonitorDMXValueChanged(int value)
×
658
{
659
    if (value == sliderValue())
×
660
        return;
×
661

662
    m_monitorValue = value;
×
663

664
    if (m_isOverriding == false)
×
665
    {
666
        {
667
            QMutexLocker locker(&m_levelValueMutex);
×
668
            m_levelValue = m_monitorValue;
×
669
        }
670

671
        if (m_slider)
×
672
            m_slider->blockSignals(true);
×
673
        setSliderValue(value, false);
×
674
        setTopLabelText(sliderValue());
×
675
        if (m_slider)
×
676
            m_slider->blockSignals(false);
×
677
    }
678
    setSliderShadowValue(value);
×
679
    updateFeedback();
×
680
}
681

682
void VCSlider::slotUniverseWritten(quint32 idx, const QByteArray &universeData)
×
683
{
684
    if (m_levelValueChanged)
×
685
        return;
×
686

687
    bool mixedDMXlevels = false;
×
688
    int monitorSliderValue = -1;
×
689
    QListIterator <LevelChannel> it(m_levelChannels);
×
690

691
    while (it.hasNext() == true)
×
692
    {
693
        LevelChannel lch(it.next());
×
694
        Fixture* fxi = m_doc->fixture(lch.fixture);
×
695
        if (fxi == NULL || fxi->universe() != idx)
×
696
            continue;
×
697

698
        if (lch.channel >= fxi->channels() ||
×
699
            fxi->address() + lch.channel >= (quint32)universeData.length())
×
700
            continue;
×
701

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

721
    // check if all the DMX channels controlled by this slider
722
    // have the same value. If so, move the widget slider or knob
723
    // to the detected position
724
    if (mixedDMXlevels == false &&
×
725
        monitorSliderValue != m_monitorValue)
×
726
    {
727
        emit monitorDMXValueChanged(monitorSliderValue);
×
728

729
        if (m_isOverriding == false)
×
730
        {
731
            // return here. At the next call of this method,
732
            // the monitor level will kick in
733
            return;
×
734
        }
735
    }
736
}
737

738
/*********************************************************************
739
 * Click & Go
740
 *********************************************************************/
741

742
void VCSlider::setClickAndGoType(ClickAndGoWidget::ClickAndGo type)
×
743
{
744
    m_cngType = type;
×
745
}
×
746

747
ClickAndGoWidget::ClickAndGo VCSlider::clickAndGoType() const
×
748
{
749
    return m_cngType;
×
750
}
751

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

772
ClickAndGoWidget *VCSlider::getClickAndGoWidget()
×
773
{
774
    return m_cngWidget;
×
775
}
776

777
void VCSlider::setClickAndGoWidgetFromLevel(uchar level)
×
778
{
779
    if (m_cngType == ClickAndGoWidget::None || m_cngWidget == NULL)
×
780
        return;
×
781

782
    if (m_cngType == ClickAndGoWidget::RGB || m_cngType == ClickAndGoWidget::CMY)
×
783
    {
784
        QPixmap px(42, 42);
×
785
        float f = 0;
×
786
        if (m_slider)
×
787
            f = SCALE(float(level), float(m_slider->minimum()),
×
788
                      float(m_slider->maximum()), float(0), float(200));
789

790
        if ((uchar)f == 0)
×
791
        {
792
            px.fill(Qt::black);
×
793
        }
794
        else
795
        {
796
            QColor modColor = m_cngRGBvalue.lighter((uchar)f);
×
797
            px.fill(modColor);
×
798
        }
799
        m_cngButton->setIcon(px);
×
800
    }
801
    else
802
        m_cngButton->setIcon(QPixmap::fromImage(m_cngWidget->getImageFromValue(level)));
×
803
}
804

805
void VCSlider::slotClickAndGoLevelChanged(uchar level)
×
806
{
807
    setSliderValue(level);
×
808
    updateFeedback();
×
809

810
    QColor col = m_cngWidget->getColorAt(level);
×
811
    QPixmap px(42, 42);
×
812
    px.fill(col);
×
813
    m_cngButton->setIcon(px);
×
814
    m_levelValueChanged = true;
×
815
}
×
816

817
void VCSlider::slotClickAndGoColorChanged(QRgb color)
×
818
{
819
    QColor col(color);
×
820
    m_cngRGBvalue = col;
×
821
    QPixmap px(42, 42);
×
822
    px.fill(col);
×
823
    m_cngButton->setIcon(px);
×
824

825
    // place the slider half way to reach white@255 and black@0
826
    setSliderValue(128);
×
827
    updateFeedback();
×
828

829
    // let's force a value change to cover all the HTP/LTP cases
830
    m_levelValueChanged = true;
×
831
}
×
832

833
void VCSlider::slotClickAndGoLevelAndPresetChanged(uchar level, QImage img)
×
834
{
835
    setSliderValue(level);
×
836
    updateFeedback();
×
837

838
    QPixmap px = QPixmap::fromImage(img);
×
839
    m_cngButton->setIcon(px);
×
840
    m_levelValueChanged = true;
×
841
}
×
842

843
/*********************************************************************
844
 * Override reset button
845
 *********************************************************************/
846

847
void VCSlider::setOverrideResetKeySequence(const QKeySequence &keySequence)
×
848
{
849
    m_overrideResetKeySequence = QKeySequence(keySequence);
×
850
}
×
851

852
QKeySequence VCSlider::overrideResetKeySequence() const
×
853
{
854
    return m_overrideResetKeySequence;
×
855
}
856

857
void VCSlider::slotResetButtonClicked()
×
858
{
859
    m_isOverriding = false;
×
860
    m_resetButton->setStyleSheet(QString("QToolButton{ background: %1; }")
×
861
                                 .arg(m_slider->palette().window().color().name()));
×
862

863
    // request to delete all the active fader channels
864
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
865
    {
866
        if (!fader.isNull())
×
867
            fader->removeAll();
×
868
    }
869

870
    emit monitorDMXValueChanged(m_monitorValue);
×
871
}
×
872

873
void VCSlider::slotKeyPressed(const QKeySequence &keySequence)
×
874
{
875
    if (isEnabled() == false)
×
876
        return;
×
877

878
    if (m_overrideResetKeySequence == keySequence)
×
879
        slotResetButtonClicked();
×
880
}
881

882
/*****************************************************************************
883
 * Playback
884
 *****************************************************************************/
885

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

905
    Function* function = m_doc->function(fid);
2✔
906
    if (function != NULL)
2✔
907
    {
908
        /* Connect to the new function */
909
        connect(function, SIGNAL(running(quint32)),
×
910
                this, SLOT(slotPlaybackFunctionRunning(quint32)));
911
        connect(function, SIGNAL(stopped(quint32)),
×
912
                this, SLOT(slotPlaybackFunctionStopped(quint32)));
913
        connect(function, SIGNAL(attributeChanged(int, qreal)),
×
914
                this, SLOT(slotPlaybackFunctionIntensityChanged(int, qreal)));
915
        if (function->type() == Function::SceneType)
×
916
        {
917
            connect(function, SIGNAL(flashing(quint32,bool)),
×
918
                    this, SLOT(slotPlaybackFunctionFlashing(quint32,bool)));
919
        }
920

921
        m_playbackFunction = fid;
×
922
    }
923
    else
924
    {
925
        /* No function attachment */
926
        m_playbackFunction = Function::invalidId();
2✔
927
    }
928
}
2✔
929

930
quint32 VCSlider::playbackFunction() const
×
931
{
932
    return m_playbackFunction;
×
933
}
934

935
void VCSlider::setPlaybackValue(uchar value)
×
936
{
937
    if (m_externalMovement == true || value == m_playbackValue)
×
938
        return;
×
939

940
    QMutexLocker locker(&m_playbackValueMutex);
×
941
    m_playbackValue = value;
×
942
    m_playbackChangeCounter = 5;
×
943
}
944

945
uchar VCSlider::playbackValue() const
2✔
946
{
947
    return m_playbackValue;
2✔
948
}
949

950
void VCSlider::notifyFunctionStarting(quint32 fid, qreal functionIntensity)
×
951
{
952
    if (mode() == Doc::Design || sliderMode() != Playback)
×
953
        return;
×
954

955
    if (fid == playbackFunction())
×
956
        return;
×
957

958
    if (m_slider != NULL)
×
959
    {
960
        int value = SCALE(1.0 - functionIntensity, 0, 1.0,
×
961
                          m_slider->minimum(), m_slider->maximum());
962
        if (m_slider->value() > value)
×
963
        {
964
            m_externalMovement = true;
×
965
            m_slider->setValue(value);
×
966
            m_externalMovement = false;
×
967

968
            Function* function = m_doc->function(m_playbackFunction);
×
969
            if (function != NULL)
×
970
            {
971
                qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
972
                adjustFunctionIntensity(function, pIntensity * intensity());
×
973
                if (value == 0 && !function->stopped())
×
974
                    function->stop(functionParent());
×
975
            }
976
        }
977
    }
978
}
979

980
void VCSlider::slotPlaybackFunctionRunning(quint32 fid)
×
981
{
982
    Q_UNUSED(fid);
983
}
×
984

985
void VCSlider::slotPlaybackFunctionStopped(quint32 fid)
×
986
{
987
    if (fid != playbackFunction())
×
988
        return;
×
989

990
    m_externalMovement = true;
×
991
    if (m_slider)
×
992
        m_slider->setValue(0);
×
993
    resetIntensityOverrideAttribute();
×
994
    updateFeedback();
×
995
    m_externalMovement = false;
×
996
}
997

998
void VCSlider::slotPlaybackFunctionIntensityChanged(int attrIndex, qreal fraction)
×
999
{
1000
    //qDebug() << "Function intensity changed" << attrIndex << fraction << m_playbackChangeCounter;
1001

1002
    if (attrIndex != Function::Intensity || m_playbackChangeCounter)
×
1003
        return;
×
1004

1005
    m_externalMovement = true;
×
1006
    if (m_slider)
×
1007
        m_slider->setValue(int(floor((qreal(m_slider->maximum()) * fraction) + 0.5)));
×
1008
    updateFeedback();
×
1009
    m_externalMovement = false;
×
1010
}
1011

1012
void VCSlider::slotPlaybackFunctionFlashing(quint32 fid, bool flashing)
×
1013
{
1014
    if (fid != playbackFunction())
×
1015
        return;
×
1016

1017
    m_externalMovement = true;
×
1018
    if (m_slider)
×
1019
        m_slider->setValue(flashing ? m_slider->maximum() : m_slider->minimum());
×
1020
    updateFeedback();
×
1021
    m_externalMovement = false;
×
1022
}
1023

1024
FunctionParent VCSlider::functionParent() const
×
1025
{
1026
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
1027
}
1028

1029
/*********************************************************************
1030
 * Submaster
1031
 *********************************************************************/
1032

1033
void VCSlider::emitSubmasterValue()
×
1034
{
1035
    Q_ASSERT(sliderMode() == Submaster);
×
1036

1037
    emit submasterValueChanged(SCALE(float(m_levelValue), float(0),
×
1038
                float(UCHAR_MAX), float(0), float(1)) * intensity());
×
1039
}
×
1040

1041
/*****************************************************************************
1042
 * DMXSource
1043
 *****************************************************************************/
1044

1045
void VCSlider::writeDMX(MasterTimer *timer, QList<Universe *> universes)
×
1046
{
1047
    if (sliderMode() == Level)
×
1048
        writeDMXLevel(timer, universes);
×
1049
    else if (sliderMode() == Playback)
×
1050
        writeDMXPlayback(timer, universes);
×
1051
}
×
1052

1053
void VCSlider::writeDMXLevel(MasterTimer *timer, QList<Universe *> universes)
×
1054
{
1055
    Q_UNUSED(timer);
1056

1057
    QMutexLocker locker(&m_levelValueMutex);
×
1058

1059
    uchar modLevel = m_levelValue;
×
1060
    int r = 0, g = 0, b = 0, c = 0, m = 0, y = 0;
×
1061

1062
    if (m_cngType == ClickAndGoWidget::RGB)
×
1063
    {
1064
        float f = 0;
×
1065
        if (m_slider)
×
1066
            f = SCALE(float(m_levelValue), float(m_slider->minimum()),
×
1067
                      float(m_slider->maximum()), float(0), float(200));
1068

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

1092
    if (m_levelValueChanged)
×
1093
    {
1094
        QListIterator <LevelChannel> it(m_levelChannels);
×
1095
        while (it.hasNext() == true)
×
1096
        {
1097
            LevelChannel lch(it.next());
×
1098
            Fixture *fxi = m_doc->fixture(lch.fixture);
×
1099
            if (fxi == NULL)
×
1100
                continue;
×
1101

1102
            quint32 universe = fxi->universe();
×
1103

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

1119
            FadeChannel *fc = fader->getChannelFader(m_doc, universes[universe], lch.fixture, lch.channel);
×
1120
            if (fc->universe() == Universe::invalid())
×
1121
            {
1122
                fader->remove(fc);
×
1123
                continue;
×
1124
            }
1125

1126
            int chType = fc->flags();
×
1127
            const QLCChannel *qlcch = fxi->channel(lch.channel);
×
1128
            if (qlcch == NULL)
×
1129
                continue;
×
1130

1131
            // set override flag if needed
1132
            if (m_isOverriding)
×
1133
                fc->addFlag(FadeChannel::Override);
×
1134

1135
            // request to autoremove LTP channels when set
1136
            if (qlcch->group() != QLCChannel::Intensity)
×
1137
                fc->addFlag(FadeChannel::AutoRemove);
×
1138

1139
            if (chType & FadeChannel::Intensity)
×
1140
            {
1141
                if (m_cngType == ClickAndGoWidget::RGB)
×
1142
                {
1143
                    if (qlcch->colour() == QLCChannel::Red)
×
1144
                        modLevel = uchar(r);
×
1145
                    else if (qlcch->colour() == QLCChannel::Green)
×
1146
                        modLevel = uchar(g);
×
1147
                    else if (qlcch->colour() == QLCChannel::Blue)
×
1148
                        modLevel = uchar(b);
×
1149
                }
1150
                else if (m_cngType == ClickAndGoWidget::CMY)
×
1151
                {
1152
                    if (qlcch->colour() == QLCChannel::Cyan)
×
1153
                        modLevel = uchar(c);
×
1154
                    else if (qlcch->colour() == QLCChannel::Magenta)
×
1155
                        modLevel = uchar(m);
×
1156
                    else if (qlcch->colour() == QLCChannel::Yellow)
×
1157
                        modLevel = uchar(y);
×
1158
                }
1159
            }
1160

1161
            fc->setStart(fc->current());
×
1162
            fc->setTarget(modLevel);
×
1163
            fc->setReady(false);
×
1164
            fc->setElapsed(0);
×
1165

1166
            //qDebug() << "VC Slider write channel" << fc->target();
1167
        }
1168
    }
1169
    m_levelValueChanged = false;
×
1170
}
×
1171

1172
void VCSlider::writeDMXPlayback(MasterTimer* timer, QList<Universe *> ua)
×
1173
{
1174
    Q_UNUSED(ua);
1175

1176
    QMutexLocker locker(&m_playbackValueMutex);
×
1177

1178
    if (m_playbackChangeCounter == 0)
×
1179
        return;
×
1180

1181
    Function* function = m_doc->function(m_playbackFunction);
×
1182
    if (function == NULL || mode() == Doc::Design)
×
1183
        return;
×
1184

1185
    uchar value = m_playbackValue;
×
1186
    qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
1187

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

1215
/*****************************************************************************
1216
 * Top label
1217
 *****************************************************************************/
1218

1219
void VCSlider::setTopLabelText(int value)
2✔
1220
{
1221
    QString text;
2✔
1222

1223
    if (valueDisplayStyle() == ExactValue)
2✔
1224
    {
1225
        text = text.asprintf("%.3d", value);
2✔
1226
    }
1227
    else
1228
    {
1229

1230
        float f = 0;
×
1231
        if (m_slider)
×
1232
            f = SCALE(float(value), float(m_slider->minimum()),
×
1233
                      float(m_slider->maximum()), float(0), float(100));
1234
        text = text.asprintf("%.3d%%", static_cast<int> (f));
×
1235
    }
1236
    m_topLabel->setText(text);
2✔
1237
    emit valueChanged(text);
2✔
1238
}
2✔
1239

1240
QString VCSlider::topLabelText()
×
1241
{
1242
    return m_topLabel->text();
×
1243
}
1244

1245
/*****************************************************************************
1246
 * Slider
1247
 *****************************************************************************/
1248

1249
void VCSlider::setSliderValue(uchar value, bool scale, bool external)
×
1250
{
1251
    if (m_slider == NULL)
×
1252
        return;
×
1253

1254
    float val = value;
×
1255

1256
    /* Scale from input value range to this slider's range */
1257
    if (scale)
×
1258
    {
1259
        val = SCALE(float(value), float(0), float(UCHAR_MAX),
×
1260
                float(m_slider->minimum()),
1261
                float(m_slider->maximum()));
1262
    }
1263

1264
    /* Request the UI to update */
1265
    if (m_slider->isSliderDown() == false && val != m_slider->value())
×
1266
       emit requestSliderUpdate(val);
×
1267

1268
    switch (sliderMode())
×
1269
    {
1270
        case Level:
×
1271
        {
1272
            if (m_monitorEnabled == true && m_isOverriding == false && m_slider->isSliderDown())
×
1273
            {
1274
                m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }"));
×
1275
                m_isOverriding = true;
×
1276
            }
1277
            setLevelValue(val, external);
×
1278
            setClickAndGoWidgetFromLevel(val);
×
1279
        }
1280
        break;
×
1281

1282
        case Playback:
×
1283
        {
1284
            setPlaybackValue(value);
×
1285
        }
1286
        break;
×
1287

1288
        case Submaster:
×
1289
        {
1290
            setLevelValue(val);
×
1291
            emitSubmasterValue();
×
1292
        }
1293
        break;
×
1294
    }
1295
}
1296

1297
void VCSlider::setSliderShadowValue(int value)
×
1298
{
1299
    if (m_widgetMode == WSlider)
×
1300
    {
1301
        ClickAndGoSlider *sl = qobject_cast<ClickAndGoSlider*> (m_slider);
×
1302
        sl->setShadowLevel(value);
×
1303
    }
1304
}
×
1305

1306
int VCSlider::sliderValue() const
×
1307
{
1308
    if (m_slider)
×
1309
        return m_slider->value();
×
1310

1311
    return 0;
×
1312
}
1313

1314
void VCSlider::setWidgetStyle(SliderWidgetStyle mode)
×
1315
{
1316
    if (mode == m_widgetMode)
×
1317
        return;
×
1318

1319
    if (mode == WKnob)
×
1320
    {
1321
        qDebug() << "Switching to knob widget";
×
1322
        disconnect(m_slider, SIGNAL(valueChanged(int)),
×
1323
                this, SLOT(slotSliderMoved(int)));
1324

1325
        QLayoutItem* item;
1326
        while ((item = m_hbox->takeAt(0)) != NULL)
×
1327
        {
1328
            delete item->widget();
×
1329
            delete item;
×
1330
        }
1331

1332
        m_slider = NULL;
×
1333

1334
        m_slider = new KnobWidget(this);
×
1335
        m_slider->setEnabled(false);
×
1336
        m_slider->setRange(levelLowLimit(), levelHighLimit());
×
1337
        m_hbox->addWidget(m_slider);
×
1338
        m_slider->show();
×
1339
        connect(m_slider, SIGNAL(valueChanged(int)),
×
1340
                this, SLOT(slotSliderMoved(int)));
1341
    }
1342
    else if (mode == WSlider)
×
1343
    {
1344
        qDebug() << "Switching to slider widget";
×
1345
        disconnect(m_slider, SIGNAL(valueChanged(int)),
×
1346
                this, SLOT(slotSliderMoved(int)));
1347

1348
        QLayoutItem* item;
1349
        while ((item = m_hbox->takeAt(0)) != NULL)
×
1350
        {
1351
            delete item->widget();
×
1352
            delete item;
×
1353
        }
1354

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

1376
VCSlider::SliderWidgetStyle VCSlider::widgetStyle() const
×
1377
{
1378
    return m_widgetMode;
×
1379
}
1380

1381
QString VCSlider::widgetStyleToString(VCSlider::SliderWidgetStyle style)
×
1382
{
1383
    if (style == VCSlider::WSlider)
×
1384
        return QString("Slider");
×
1385
    else if (style == VCSlider::WKnob)
×
1386
        return QString("Knob");
×
1387

1388
    return QString();
×
1389
}
1390

1391
VCSlider::SliderWidgetStyle VCSlider::stringToWidgetStyle(QString style)
×
1392
{
1393
    if (style == "Slider")
×
1394
        return VCSlider::WSlider;
×
1395
    else if (style == "Knob")
×
1396
        return VCSlider::WKnob;
×
1397

1398
    return VCSlider::WSlider;
×
1399
}
1400

1401
void VCSlider::updateFeedback()
×
1402
{
1403
    int fbv = 0;
×
1404
    if (m_slider)
×
1405
    {
1406
        if (invertedAppearance() == true)
×
1407
            fbv = m_slider->maximum() - m_slider->value() + m_slider->minimum();
×
1408
        else
1409
            fbv = m_slider->value();
×
1410
        fbv = int(SCALE(float(fbv), float(m_slider->minimum()),
×
1411
                        float(m_slider->maximum()), float(0), float(UCHAR_MAX)));
1412
    }
1413
    sendFeedback(fbv);
×
1414
}
×
1415

1416
void VCSlider::slotSliderMoved(int value)
2✔
1417
{
1418
    /* Set text for the top label */
1419
    setTopLabelText(value);
2✔
1420

1421
    /* Do the rest only if the slider is being moved by the user */
1422
    if (m_slider->isSliderDown() == false)
2✔
1423
        return;
2✔
1424

1425
    setSliderValue(value, false);
×
1426

1427
    updateFeedback();
×
1428
}
1429

1430
/*****************************************************************************
1431
 * Bottom label
1432
 *****************************************************************************/
1433
void VCSlider::setBottomLabelText(const QString& text)
×
1434
{
1435
    m_bottomLabel->setText(text);
×
1436
}
×
1437

1438
QString VCSlider::bottomLabelText()
×
1439
{
1440
    return m_bottomLabel->text();
×
1441
}
1442

1443
/*****************************************************************************
1444
 * External input
1445
 *****************************************************************************/
1446

1447
void VCSlider::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
1448
{
1449
    /* Don't let input data through in design mode or if disabled */
1450
    if (acceptsInput() == false)
×
1451
        return;
×
1452

1453
    quint32 pagedCh = (page() << 16) | channel;
×
1454

1455
    if (checkInputSource(universe, pagedCh, value, sender(), sliderInputSourceId))
×
1456
    {
1457
        if (m_slider)
×
1458
        {
1459
            /* When 'values catching" is enabled, controllers that do not have motorized faders
1460
             * can catch up with the current slider value by entering a certain threshold
1461
             * or by 'surpassing' the current value */
1462
            if (catchValues())
×
1463
            {
1464
                uchar currentValue = sliderValue();
×
1465

1466
                // filter 'out of threshold' cases
1467
                if (m_lastInputValue == -1 ||
×
1468
                    (m_lastInputValue < currentValue - VALUE_CATCHING_THRESHOLD && value < currentValue - VALUE_CATCHING_THRESHOLD) ||
×
1469
                    (m_lastInputValue > currentValue + VALUE_CATCHING_THRESHOLD && value > currentValue + VALUE_CATCHING_THRESHOLD))
×
1470
                {
1471
                    m_lastInputValue = value;
×
1472
                    return;
×
1473
                }
1474
            }
1475

1476
            if (m_monitorEnabled == true && m_isOverriding == false)
×
1477
            {
1478
                m_resetButton->setStyleSheet(QString("QToolButton{ background: red; }"));
×
1479
                m_isOverriding = true;
×
1480
            }
1481

1482
            if (invertedAppearance())
×
1483
                value = UCHAR_MAX - value;
×
1484

1485
            setSliderValue(value, true, true);
×
1486
            m_lastInputValue = value;
×
1487
        }
1488
    }
1489
    else if (checkInputSource(universe, pagedCh, value, sender(), overrideResetInputSourceId))
×
1490
    {
1491
        if (value > 0)
×
1492
            slotResetButtonClicked();
×
1493
    }
1494
}
1495

1496
void VCSlider::adjustIntensity(qreal val)
×
1497
{
1498
    VCWidget::adjustIntensity(val);
×
1499

1500
    if (sliderMode() == Playback)
×
1501
    {
1502
        Function* function = m_doc->function(m_playbackFunction);
×
1503
        if (function == NULL || mode() == Doc::Design)
×
1504
            return;
×
1505

1506
        qreal pIntensity = qreal(m_playbackValue) / qreal(UCHAR_MAX);
×
1507
        adjustFunctionIntensity(function, pIntensity * intensity());
×
1508
    }
1509
    else if (sliderMode() == Level)
×
1510
    {
1511
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
1512
        {
1513
            if (!fader.isNull())
×
1514
                fader->adjustIntensity(val);
×
1515
        }
1516
    }
1517
}
1518

1519
/*****************************************************************************
1520
 * Load & Save
1521
 *****************************************************************************/
1522

1523
bool VCSlider::loadXML(QXmlStreamReader &root)
1✔
1524
{
1525
    bool visible = false;
1✔
1526
    int x = 0;
1✔
1527
    int y = 0;
1✔
1528
    int w = 0;
1✔
1529
    int h = 0;
1✔
1530

1531
    SliderMode sliderMode = Playback;
1✔
1532
    QString str;
2✔
1533

1534
    if (root.name() != KXMLQLCVCSlider)
1✔
1535
    {
1536
        qWarning() << Q_FUNC_INFO << "Slider node not found";
×
1537
        return false;
×
1538
    }
1539

1540
    /* Widget commons */
1541
    loadXMLCommon(root);
1✔
1542

1543
    QXmlStreamAttributes attrs = root.attributes();
1✔
1544

1545
    /* Widget style */
1546
    if (attrs.hasAttribute(KXMLQLCVCSliderWidgetStyle))
1✔
1547
        setWidgetStyle(stringToWidgetStyle(attrs.value(KXMLQLCVCSliderWidgetStyle).toString()));
×
1548

1549
    if (attrs.value(KXMLQLCVCSliderInvertedAppearance).toString() == "false")
1✔
1550
        setInvertedAppearance(false);
×
1551
    else
1552
        setInvertedAppearance(true);
1✔
1553

1554
    /* Values catching */
1555
    if (attrs.hasAttribute(KXMLQLCVCSliderCatchValues))
1✔
1556
        setCatchValues(true);
×
1557

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

1576
            str = mAttrs.value(KXMLQLCVCSliderValueDisplayStyle).toString();
×
1577
            setValueDisplayStyle(stringToValueDisplayStyle(str));
×
1578

1579
            if (mAttrs.hasAttribute(KXMLQLCVCSliderClickAndGoType))
×
1580
            {
1581
                str = mAttrs.value(KXMLQLCVCSliderClickAndGoType).toString();
×
1582
                setClickAndGoType(ClickAndGoWidget::stringToClickAndGoType(str));
×
1583
            }
1584

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

1618
    /* Set the mode last, after everything else has been set */
1619
    setSliderMode(sliderMode);
1✔
1620

1621
    return true;
1✔
1622
}
1623

1624
bool VCSlider::loadXMLLevel(QXmlStreamReader &level_root)
×
1625
{
1626
    QString str;
×
1627

1628
    if (level_root.name() != KXMLQLCVCSliderLevel)
×
1629
    {
1630
        qWarning() << Q_FUNC_INFO << "Slider level node not found";
×
1631
        return false;
×
1632
    }
1633

1634
    QXmlStreamAttributes attrs = level_root.attributes();
×
1635

1636
    /* Level low limit */
1637
    str = attrs.value(KXMLQLCVCSliderLevelLowLimit).toString();
×
1638
    setLevelLowLimit(str.toInt());
×
1639

1640
    /* Level high limit */
1641
    str = attrs.value(KXMLQLCVCSliderLevelHighLimit).toString();
×
1642
    setLevelHighLimit(str.toInt());
×
1643

1644
    /* Level value */
1645
    str = attrs.value(KXMLQLCVCSliderLevelValue).toString();
×
1646
    setLevelValue(str.toInt());
×
1647

1648
    QXmlStreamReader::TokenType tType = level_root.readNext();
×
1649

1650
    if (tType == QXmlStreamReader::EndElement)
×
1651
    {
1652
        level_root.readNext();
×
1653
        return true;
×
1654
    }
1655

1656
    if (tType == QXmlStreamReader::Characters)
×
1657
        tType = level_root.readNext();
×
1658

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

1681
    return true;
×
1682
}
1683

1684
bool VCSlider::loadXMLPlayback(QXmlStreamReader &pb_root)
×
1685
{
1686
    if (pb_root.name() != KXMLQLCVCSliderPlayback)
×
1687
    {
1688
        qWarning() << Q_FUNC_INFO << "Slider playback node not found";
×
1689
        return false;
×
1690
    }
1691

1692
    /* Children */
1693
    while (pb_root.readNextStartElement())
×
1694
    {
1695
        if (pb_root.name() == KXMLQLCVCSliderPlaybackFunction)
×
1696
        {
1697
            /* Function */
1698
            setPlaybackFunction(pb_root.readElementText().toUInt());
×
1699
        }
1700
        else
1701
        {
1702
            qWarning() << Q_FUNC_INFO << "Unknown slider playback tag:" << pb_root.name().toString();
×
1703
            pb_root.skipCurrentElement();
×
1704
        }
1705
    }
1706

1707
    return true;
×
1708
}
1709

1710
bool VCSlider::saveXML(QXmlStreamWriter *doc)
×
1711
{
1712
    QString str;
×
1713

1714
    Q_ASSERT(doc != NULL);
×
1715

1716
    /* VC Slider entry */
1717
    doc->writeStartElement(KXMLQLCVCSlider);
×
1718

1719
    saveXMLCommon(doc);
×
1720

1721
    /* Widget style */
1722
    doc->writeAttribute(KXMLQLCVCSliderWidgetStyle, widgetStyleToString(widgetStyle()));
×
1723

1724
    /* Inverted appearance */
1725
    if (invertedAppearance() == true)
×
1726
        doc->writeAttribute(KXMLQLCVCSliderInvertedAppearance, "true");
×
1727
    else
1728
        doc->writeAttribute(KXMLQLCVCSliderInvertedAppearance, "false");
×
1729

1730
    /* Values catching */
1731
    if (catchValues() == true)
×
1732
        doc->writeAttribute(KXMLQLCVCSliderCatchValues, "true");
×
1733

1734
    /* Window state */
1735
    saveXMLWindowState(doc);
×
1736

1737
    /* Appearance */
1738
    saveXMLAppearance(doc);
×
1739

1740
    /* External input */
1741
    saveXMLInput(doc, inputSource(sliderInputSourceId));
×
1742

1743
    /* SliderMode */
1744
    doc->writeStartElement(KXMLQLCVCSliderMode);
×
1745

1746
    /* Value display style */
1747
    str = valueDisplayStyleToString(valueDisplayStyle());
×
1748
    doc->writeAttribute(KXMLQLCVCSliderValueDisplayStyle, str);
×
1749

1750
    /* Click And Go type */
1751
    str = ClickAndGoWidget::clickAndGoTypeToString(m_cngType);
×
1752
    doc->writeAttribute(KXMLQLCVCSliderClickAndGoType, str);
×
1753

1754
    /* Monitor channels */
1755
    if (sliderMode() == Level)
×
1756
    {
1757
        if (channelsMonitorEnabled() == true)
×
1758
            doc->writeAttribute(KXMLQLCVCSliderLevelMonitor, "true");
×
1759
        else
1760
            doc->writeAttribute(KXMLQLCVCSliderLevelMonitor, "false");
×
1761
    }
1762

1763
    doc->writeCharacters(sliderModeToString(m_sliderMode));
×
1764

1765
    /* End the <SliderMode> tag */
1766
    doc->writeEndElement();
×
1767

1768
    if (sliderMode() == Level && channelsMonitorEnabled() == true)
×
1769
    {
1770
        doc->writeStartElement(KXMLQLCVCSliderOverrideReset);
×
1771
        if (m_overrideResetKeySequence.toString().isEmpty() == false)
×
1772
            doc->writeTextElement(KXMLQLCVCWidgetKey, m_overrideResetKeySequence.toString());
×
1773
        saveXMLInput(doc, inputSource(overrideResetInputSourceId));
×
1774
        doc->writeEndElement();
×
1775
    }
1776

1777
    /* Level */
1778
    doc->writeStartElement(KXMLQLCVCSliderLevel);
×
1779
    /* Level low limit */
1780
    doc->writeAttribute(KXMLQLCVCSliderLevelLowLimit, QString::number(levelLowLimit()));
×
1781
    /* Level high limit */
1782
    doc->writeAttribute(KXMLQLCVCSliderLevelHighLimit, QString::number(levelHighLimit()));
×
1783
    /* Level value */
1784
    doc->writeAttribute(KXMLQLCVCSliderLevelValue, QString::number(levelValue()));
×
1785

1786
    /* Level channels */
1787
    QListIterator <LevelChannel> it(m_levelChannels);
×
1788
    while (it.hasNext() == true)
×
1789
    {
1790
        LevelChannel lch(it.next());
×
1791
        lch.saveXML(doc);
×
1792
    }
1793

1794
    /* End the <Level> tag */
1795
    doc->writeEndElement();
×
1796

1797
    /* Playback */
1798
    doc->writeStartElement(KXMLQLCVCSliderPlayback);
×
1799
    /* Playback function */
1800
    doc->writeTextElement(KXMLQLCVCSliderPlaybackFunction, QString::number(playbackFunction()));
×
1801
    /* End the <Playback> tag */
1802
    doc->writeEndElement();
×
1803

1804
    /* End the <Slider> tag */
1805
    doc->writeEndElement();
×
1806

1807
    return true;
×
1808
}
1809

1810
/****************************************************************************
1811
 * LevelChannel implementation
1812
 ****************************************************************************/
1813

1814
VCSlider::LevelChannel::LevelChannel(quint32 fid, quint32 ch)
×
1815
{
1816
    this->fixture = fid;
×
1817
    this->channel = ch;
×
1818
}
×
1819

1820
VCSlider::LevelChannel::LevelChannel(const LevelChannel& lc)
×
1821
{
1822
    *this = lc;
×
1823
}
×
1824

1825
VCSlider::LevelChannel &VCSlider::LevelChannel::operator=(const VCSlider::LevelChannel &lc)
×
1826
{
1827
    if (this != &lc)
×
1828
    {
1829
        this->fixture = lc.fixture;
×
1830
        this->channel = lc.channel;
×
1831
    }
1832

1833
    return *this;
×
1834
}
1835

1836
bool VCSlider::LevelChannel::operator==(const LevelChannel& lc) const
×
1837
{
1838
    return (this->fixture == lc.fixture && this->channel == lc.channel);
×
1839
}
1840

1841
bool VCSlider::LevelChannel::operator<(const LevelChannel& lc) const
×
1842
{
1843
    if (this->fixture < lc.fixture)
×
1844
        return true;
×
1845
    else if (this->fixture == lc.fixture && this->channel < lc.channel)
×
1846
        return true;
×
1847
    else
1848
        return false;
×
1849
}
1850

1851
void VCSlider::LevelChannel::saveXML(QXmlStreamWriter *doc) const
×
1852
{
1853
    Q_ASSERT(doc != NULL);
×
1854

1855
    doc->writeStartElement(KXMLQLCVCSliderChannel);
×
1856

1857
    doc->writeAttribute(KXMLQLCVCSliderChannelFixture,
×
1858
                       QString::number(this->fixture));
×
1859

1860
    doc->writeCharacters(QString::number(this->channel));
×
1861
    doc->writeEndElement();
×
1862
}
×
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