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

mcallegari / qlcplus / 4680920983

pending completion
4680920983

push

github

Massimo Callegari
ui: add missing change to previous commit

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

15285 of 54429 relevant lines covered (28.08%)

20271.17 hits per line

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

17.23
/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

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

547
/*****************************************************************************
548
 * Level
549
 *****************************************************************************/
550

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

668
    m_monitorValue = value;
×
669

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

888
/*****************************************************************************
889
 * Playback
890
 *****************************************************************************/
891

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1035
/*********************************************************************
1036
 * Submaster
1037
 *********************************************************************/
1038

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

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

1047
/*****************************************************************************
1048
 * DMXSource
1049
 *****************************************************************************/
1050

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

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

1063
    QMutexLocker locker(&m_levelValueMutex);
×
1064

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1182
    QMutexLocker locker(&m_playbackValueMutex);
×
1183

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

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

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

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

1221
/*****************************************************************************
1222
 * Top label
1223
 *****************************************************************************/
1224

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

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

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

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

1251
/*****************************************************************************
1252
 * Slider
1253
 *****************************************************************************/
1254

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

1260
    float val = value;
×
1261

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

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

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

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

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

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

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

1317
    return 0;
×
1318
}
1319

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

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

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

1338
        m_slider = NULL;
×
1339

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

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

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

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

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

1394
    return QString();
×
1395
}
1396

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

1404
    return VCSlider::WSlider;
×
1405
}
1406

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

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

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

1431
    setSliderValue(value, false);
×
1432

1433
    updateFeedback();
×
1434
}
1435

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

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

1449
/*****************************************************************************
1450
 * External input
1451
 *****************************************************************************/
1452

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1627
    return true;
1✔
1628
}
1629

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

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

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

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

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

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

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

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

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

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

1687
    return true;
×
1688
}
1689

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

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

1713
    return true;
×
1714
}
1715

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

1720
    Q_ASSERT(doc != NULL);
×
1721

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

1725
    saveXMLCommon(doc);
×
1726

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1813
    return true;
×
1814
}
1815

1816
/****************************************************************************
1817
 * LevelChannel implementation
1818
 ****************************************************************************/
1819

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

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

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

1839
    return *this;
×
1840
}
1841

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

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

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

1861
    doc->writeStartElement(KXMLQLCVCSliderChannel);
×
1862

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

1866
    doc->writeCharacters(QString::number(this->channel));
×
1867
    doc->writeEndElement();
×
1868
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc