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

mcallegari / qlcplus / 8892924138

30 Apr 2024 10:03AM UTC coverage: 32.068% (-0.006%) from 32.074%
8892924138

push

github

web-flow
Merge pull request #1537 from hjtappe/limited-gobo-control

VC Click & Go Gobo control on limited-range knobs and sliders

2 of 27 new or added lines in 2 files covered. (7.41%)

3 existing lines in 2 files now uncovered.

15395 of 48008 relevant lines covered (32.07%)

22931.71 hits per line

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

17.1
/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;
×
NEW
575
    if (m_cngWidget != NULL)
×
NEW
576
        m_cngWidget->setLevelLowLimit(value);
×
UNCOV
577
}
×
578

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

584
void VCSlider::setLevelHighLimit(uchar value)
×
585
{
586
    m_levelHighLimit = value;
×
NEW
587
    if (m_cngWidget != NULL)
×
NEW
588
        m_cngWidget->setLevelHighLimit(value);
×
UNCOV
589
}
×
590

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

596
void VCSlider::setChannelsMonitorEnabled(bool enable)
×
597
{
598
    m_monitorEnabled = enable;
×
599

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

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

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

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

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

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

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

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

666
    m_monitorValue = value;
×
667

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

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

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

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

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

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

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

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

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

742
/*********************************************************************
743
 * Click & Go
744
 *********************************************************************/
745

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

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

756
void VCSlider::setupClickAndGoWidget()
×
757
{
758
    if (m_cngWidget != NULL)
×
759
    {
760
        qDebug() << Q_FUNC_INFO << "Level channel: " << m_levelChannels.size() << "type: " << m_cngType;
×
761
        if (m_cngType == ClickAndGoWidget::Preset && m_levelChannels.size() > 0)
×
762
        {
763
            LevelChannel lChan = m_levelChannels.first();
×
764
            Fixture *fxi = m_doc->fixture(lChan.fixture);
×
765
            if (fxi != NULL)
×
766
            {
767
                const QLCChannel *chan = fxi->channel(lChan.channel);
×
768
                m_cngWidget->setType(m_cngType, chan);
×
NEW
769
                m_cngWidget->setLevelLowLimit(this->levelLowLimit());
×
NEW
770
                m_cngWidget->setLevelHighLimit(this->levelHighLimit());
×
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
{
NEW
813
    setSliderValue(level, false, false);
×
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
{
NEW
841
    setSliderValue(level, false, false);
×
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