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

mcallegari / qlcplus / 6915335944

18 Nov 2023 05:29PM UTC coverage: 32.011% (-0.002%) from 32.013%
6915335944

push

github

mcallegari
vc/animation: improve signals towards web interface

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

4 existing lines in 1 file now uncovered.

15109 of 47200 relevant lines covered (32.01%)

23538.45 hits per line

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

0.0
/ui/src/virtualconsole/vcmatrix.cpp
1
/*
2
  Q Light Controller Plus
3
  vcmatrix.cpp
4

5
  Copyright (c) Massimo Callegari
6

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

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

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

20
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QWidgetAction>
23
#include <QComboBox>
24
#include <QSettings>
25
#include <QLayout>
26
#include <QDebug>
27
#include <QTimer>
28
#include <QLabel>
29
#include <QMenu>
30
#include <math.h>
31

32
#include "vcmatrixproperties.h"
33
#include "vcpropertieseditor.h"
34
#include "clickandgoslider.h"
35
#include "clickandgowidget.h"
36
#include "knobwidget.h"
37
#include "qlcmacros.h"
38
#include "rgbalgorithm.h"
39
#include "flowlayout.h"
40
#include "rgbmatrix.h"
41
#include "vcmatrix.h"
42
#include "function.h"
43
#include "rgbtext.h"
44
#include "doc.h"
45

46
#define UPDATE_TIMEOUT 50
47

48
static const QString controlBtnSS = "QPushButton { background-color: %1; height: 32px; border: 2px solid #6A6A6A; border-radius: 5px; }"
49
                                    "QPushButton:pressed { border: 2px solid #0000FF; }"
50
                                    "QPushButton:disabled { border: 2px solid #BBBBBB; color: #8f8f8f }";
51

52
const QSize VCMatrix::defaultSize(QSize(160, 120));
53

54
VCMatrix::VCMatrix(QWidget *parent, Doc *doc)
×
55
    : VCWidget(parent, doc)
56
    , m_sliderExternalMovement(false)
57
    , m_matrixID(Function::invalidId())
×
58
    , m_instantApply(true)
59
    , m_visibilityMask(VCMatrix::defaultVisibilityMask())
×
60
{
61
    /* Set the class name "VCMatrix" as the object name as well */
62
    setObjectName(VCMatrix::staticMetaObject.className());
×
63
    setFrameStyle(KVCFrameStyleSunken);
×
64

65
    QHBoxLayout *hBox = new QHBoxLayout(this);
×
66
    //hBox->setContentsMargins(3, 3, 3, 10);
67
    //hBox->setSpacing(5);
68

69
    m_slider = new ClickAndGoSlider();
×
70
    m_slider->setSliderStyleSheet(CNG_DEFAULT_STYLE);
×
71
    m_slider->setFixedWidth(32);
×
72
    m_slider->setRange(0, 255);
×
73
    m_slider->setPageStep(1);
×
74
    m_slider->setInvertedAppearance(false);
×
75
    hBox->addWidget(m_slider);
×
76

77
    connect(m_slider, SIGNAL(valueChanged(int)),
×
78
            this, SLOT(slotSliderMoved(int)));
79

80
    QVBoxLayout *vbox = new QVBoxLayout();
×
81

82
    m_startColorButton = new QToolButton(this);
×
83
    m_startColorButton->setFixedSize(48, 48);
×
84
    m_startColorButton->setIconSize(QSize(42, 42));
×
85

86
    QWidgetAction* scAction = new QWidgetAction(this);
×
87
    m_scCnGWidget = new ClickAndGoWidget();
×
88
    m_scCnGWidget->setType(ClickAndGoWidget::RGB, NULL);
×
89
    scAction->setDefaultWidget(m_scCnGWidget);
×
90
    QMenu *startColorMenu = new QMenu();
×
91
    startColorMenu->addAction(scAction);
×
92
    m_startColorButton->setMenu(startColorMenu);
×
93
    m_startColorButton->setPopupMode(QToolButton::InstantPopup);
×
94

95
    connect(m_scCnGWidget, SIGNAL(colorChanged(QRgb)),
×
96
            this, SLOT(slotStartColorChanged(QRgb)));
97

98
    m_endColorButton = new QToolButton(this);
×
99
    m_endColorButton->setFixedSize(48, 48);
×
100
    m_endColorButton->setIconSize(QSize(42, 42));
×
101

102
    QWidgetAction* ecAction = new QWidgetAction(this);
×
103
    m_ecCnGWidget = new ClickAndGoWidget();
×
104
    m_ecCnGWidget->setType(ClickAndGoWidget::RGB, NULL);
×
105
    ecAction->setDefaultWidget(m_ecCnGWidget);
×
106
    QMenu *endColorMenu = new QMenu();
×
107
    endColorMenu->addAction(ecAction);
×
108
    m_endColorButton->setMenu(endColorMenu);
×
109
    m_endColorButton->setPopupMode(QToolButton::InstantPopup);
×
110

111
    connect(m_ecCnGWidget, SIGNAL(colorChanged(QRgb)),
×
112
            this, SLOT(slotEndColorChanged(QRgb)));
113

114
    m_label = new QLabel(this);
×
115
    m_label->setAlignment(Qt::AlignCenter);
×
116
    m_label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
×
117
    vbox->addWidget(m_label);
×
118

119
    QHBoxLayout *btnHbox = new QHBoxLayout();
×
120

121
    btnHbox->addWidget(m_startColorButton);
×
122
    btnHbox->addWidget(m_endColorButton);
×
123

124
    vbox->addLayout(btnHbox);
×
125

126
    m_presetCombo = new QComboBox(this);
×
127
    //m_presetCombo->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
128
    m_presetCombo->addItems(RGBAlgorithm::algorithms(m_doc));
×
129
    connect(m_presetCombo, SIGNAL(currentIndexChanged(QString)),
×
130
            this, SLOT(slotAnimationChanged(QString)));
131
    vbox->addWidget(m_presetCombo);
×
132

133
    hBox->addLayout(vbox);
×
134

135
    m_controlsLayout = new FlowLayout();
×
136
    vbox->addLayout(m_controlsLayout);
×
137

138
    setType(VCWidget::AnimationWidget);
×
139
    setCaption(QString());
×
140
    /* Initial size */
141
    QSettings settings;
×
142
    QVariant var = settings.value(SETTINGS_RGBMATRIX_SIZE);
×
143
    if (var.isValid() == true)
×
144
        resize(var.toSize());
×
145
    else
146
        resize(defaultSize);
×
147

148
    /* Update timer */
149
    m_updateTimer = new QTimer(this);
×
150
    connect(m_updateTimer, SIGNAL(timeout()),
×
151
            this, SLOT(slotUpdate()));
152
    m_updateTimer->setSingleShot(true);
×
153

154
    /* Update the slider according to current mode */
155
    slotModeChanged(m_doc->mode());
×
156
    setLiveEdit(m_liveEdit);
×
157
}
×
158

159
VCMatrix::~VCMatrix()
×
160
{
161
    foreach(VCMatrixControl* control, m_controls)
×
162
    {
163
        delete control;
×
164
    }
165
}
×
166

167
void VCMatrix::setID(quint32 id)
×
168
{
169
    VCWidget::setID(id);
×
170

171
    if (caption().isEmpty())
×
172
        setCaption(tr("Animation %1").arg(id));
×
173
}
×
174

175
/*********************************************************************
176
 * Clipboard
177
 *********************************************************************/
178

179
VCWidget *VCMatrix::createCopy(VCWidget *parent)
×
180
{
181
    Q_ASSERT(parent != NULL);
×
182

183
    VCMatrix* matrix = new VCMatrix(parent, m_doc);
×
184
    if (matrix->copyFrom(this) == false)
×
185
    {
186
        delete matrix;
×
187
        matrix = NULL;
×
188
    }
189

190
    return matrix;
×
191
}
192

193
bool VCMatrix::copyFrom(const VCWidget* widget)
×
194
{
195
    const VCMatrix* matrix = qobject_cast <const VCMatrix*> (widget);
×
196
    if (matrix == NULL)
×
197
        return false;
×
198

199
    /* Copy vcmatrix-specific stuff */
200
    setFunction(matrix->function());
×
201
    setInstantChanges(matrix->instantChanges());
×
202
    setVisibilityMask(matrix->visibilityMask());
×
203

204
    resetCustomControls();
×
205
    foreach (VCMatrixControl const* control, matrix->customControls())
×
206
    {
207
        addCustomControl(*control);
×
208
    }
209

210
    /* Copy common stuff */
211
    return VCWidget::copyFrom(widget);
×
212
}
213

214
/*********************************************************************
215
 * GUI
216
 *********************************************************************/
217

218
void VCMatrix::setCaption(const QString &text)
×
219
{
220
    VCWidget::setCaption(text);
×
221
    m_label->setText(text);
×
222
}
×
223

224
void VCMatrix::enableWidgetUI(bool enable)
×
225
{
226
    m_slider->setEnabled(enable);
×
227
    m_startColorButton->setEnabled(enable);
×
228
    m_endColorButton->setEnabled(enable);
×
229
    m_presetCombo->setEnabled(enable);
×
230

231
    foreach(QWidget *ctlBtn, m_controls.keys())
×
232
        ctlBtn->setEnabled(enable);
×
233

234
    // Update buttons state
235
    if (enable)
×
236
        slotUpdate();
×
237
}
×
238

239
void VCMatrix::slotSetSliderValue(int value)
×
240
{
241
    m_slider->setValue(value);
×
242
    slotSliderMoved(value);
×
243
}
×
244

245
void VCMatrix::slotSliderMoved(int value)
×
246
{
247
    Function* function = m_doc->function(m_matrixID);
×
UNCOV
248
    if (function == NULL || mode() == Doc::Design)
×
249
        return;
×
250

251
    if (m_sliderExternalMovement)
×
252
        return;
×
253

254
    if (value == 0)
×
255
    {
256
        // Make sure we ignore the fade out time
257
        adjustFunctionIntensity(function, 0);
×
258
        if (function->stopped() == false)
×
259
        {
260
            function->stop(functionParent());
×
261
            resetIntensityOverrideAttribute();
×
262
        }
263
    }
264
    else
265
    {
266
        qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
267
        emit functionStarting(m_matrixID, pIntensity);
×
268
        adjustFunctionIntensity(function, pIntensity * intensity());
×
269
        if (function->stopped() == true)
×
270
        {
271
            // TODO once #758 is fixed: function started by a fader -> override fade in time
272
            function->start(m_doc->masterTimer(), functionParent());
×
273
        }
274
    }
275

NEW
276
    emit sliderValueChanged(value);
×
277
}
278

279
int VCMatrix::sliderValue()
×
280
{
281
    return m_slider->value();
×
282
}
283

284
void VCMatrix::slotSetStartColor(QColor color)
×
285
{
286
    RGBMatrix *matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
287
    if (matrix == NULL)
×
288
        return;
×
289

290
    if (matrix->startColor() != color)
×
291
    {
292
        matrix->setStartColor(color);
×
293
        emit startColorChanged();
×
294
    }
295
}
296

297
QColor VCMatrix::startColor()
×
298
{
299
    RGBMatrix *matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
300
    if (matrix == NULL)
×
301
        return QColor();
×
302

303
    return matrix->startColor();
×
304
}
305

306
void VCMatrix::slotStartColorChanged(QRgb color)
×
307
{
308
    QColor col(color);
×
309
    slotSetStartColor(col);
×
310
    QPixmap px(42, 42);
×
311
    px.fill(col);
×
312
    m_startColorButton->setIcon(px);
×
313

314
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
315
    if (matrix == NULL || mode() == Doc::Design)
×
316
        return;
×
317

318
    matrix->setStartColor(col);
×
319
    if (instantChanges() == true)
×
320
        matrix->updateColorDelta();
×
321
}
322

323
void VCMatrix::slotSetEndColor(QColor color)
×
324
{
325
    RGBMatrix *matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
326
    if (matrix == NULL)
×
327
        return;
×
328

329
    if (matrix->endColor() != color)
×
330
    {
331
        matrix->setEndColor(color);
×
332
        emit endColorChanged();
×
333
    }
334
}
335

336
QColor VCMatrix::endColor()
×
337
{
338
    RGBMatrix *matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
339
    if (matrix == NULL)
×
340
        return QColor();
×
341

342
    return matrix->endColor();
×
343
}
344

345
void VCMatrix::slotEndColorChanged(QRgb color)
×
346
{
347
    QColor col(color);
×
348
    slotSetEndColor(col);
×
349
    QPixmap px(42, 42);
×
350
    px.fill(col);
×
351
    m_endColorButton->setIcon(px);
×
352

353
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
354
    if (matrix == NULL || mode() == Doc::Design)
×
355
        return;
×
356

357
    matrix->setEndColor(col);
×
358
    if (instantChanges() == true)
×
359
        matrix->updateColorDelta();
×
360
}
361

362
void VCMatrix::slotSetAnimationValue(QString name)
×
363
{
364
    m_presetCombo->setCurrentText(name);
×
365
    slotAnimationChanged(name);
×
366
}
×
367

368
void VCMatrix::slotAnimationChanged(QString name)
×
369
{
370
    emit animationValueChanged(name);
×
371
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
372
    if (matrix == NULL || mode() == Doc::Design)
×
373
        return;
×
374

375
    RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, name);
×
376
    matrix->setAlgorithm(algo);
×
377
    if (instantChanges() == true)
×
378
        matrix->updateColorDelta();
×
379
}
380

381
QString VCMatrix::animationValue()
×
382
{
383
    return m_presetCombo->currentText();
×
384
}
385

386
void VCMatrix::setVisibilityMask(quint32 mask)
×
387
{
388
    if (mask & ShowSlider) m_slider->show();
×
389
    else m_slider->hide();
×
390

391
    if (mask & ShowLabel) m_label->show();
×
392
    else m_label->hide();
×
393

394
    if (mask & ShowStartColorButton) m_startColorButton->show();
×
395
    else m_startColorButton->hide();
×
396

397
    if (mask & ShowEndColorButton) m_endColorButton->show();
×
398
    else m_endColorButton->hide();
×
399

400
    if (mask & ShowPresetCombo) m_presetCombo->show();
×
401
    else m_presetCombo->hide();
×
402

403
    m_visibilityMask = mask;
×
404
}
×
405

406
quint32 VCMatrix::visibilityMask() const
×
407
{
408
    return m_visibilityMask;
×
409
}
410

411
quint32 VCMatrix::defaultVisibilityMask()
×
412
{
413
    return ShowSlider
414
        | ShowLabel
415
        | ShowStartColorButton
416
        | ShowEndColorButton
417
        | ShowPresetCombo
×
418
        ;
419
}
420

421
/*********************************************************************
422
 * Properties
423
 *********************************************************************/
424

425
void VCMatrix::editProperties()
×
426
{
427
    VCMatrixProperties prop(this, m_doc);
×
428
    if (prop.exec() == QDialog::Accepted)
×
429
        m_doc->setModified();
×
430
}
×
431

432
/*************************************************************************
433
 * VCWidget-inherited
434
 *************************************************************************/
435

436
void VCMatrix::adjustIntensity(qreal val)
×
437
{
438
    VCWidget::adjustIntensity(val);
×
439
    this->slotSliderMoved(this->m_slider->value());
×
440
}
×
441

442
/*********************************************************************
443
 * Function attachment
444
 *********************************************************************/
445

446
void VCMatrix::setFunction(quint32 id)
×
447
{
448
    Function *old = m_doc->function(m_matrixID);
×
449
    if (old != NULL)
×
450
    {
451
        disconnect(old, SIGNAL(stopped(quint32)),
×
452
                this, SLOT(slotFunctionStopped()));
453
        disconnect(old, SIGNAL(changed(quint32)),
×
454
                this, SLOT(slotFunctionChanged()));
455
    }
456

457
    RGBMatrix* matrix = qobject_cast<RGBMatrix*> (m_doc->function(id));
×
458

459
    if (matrix == NULL)
×
460
        m_matrixID = Function::invalidId();
×
461
    else
462
    {
463
        m_matrixID = id;
×
464
        connect(matrix, SIGNAL(stopped(quint32)),
×
465
                this, SLOT(slotFunctionStopped()));
466
        connect(matrix, SIGNAL(changed(quint32)),
×
467
                this, SLOT(slotFunctionChanged()));
468
    }
469

470
    slotUpdate();
×
471
}
×
472

473
quint32 VCMatrix::function() const
×
474
{
475
    return m_matrixID;
×
476
}
477

478
void VCMatrix::notifyFunctionStarting(quint32 fid, qreal functionIntensity)
×
479
{
480
    if (mode() == Doc::Design)
×
481
        return;
×
482

483
    if (fid == m_matrixID)
×
484
        return;
×
485

486
    int value = SCALE(1.0 - functionIntensity,
×
487
            0, 1.0,
488
            m_slider->minimum(), m_slider->maximum());
489
    if (m_slider->value() > value)
×
490
    {
491
        m_sliderExternalMovement = true;
×
492
        m_slider->setValue(value);
×
493
        m_sliderExternalMovement = false;
×
494

495
        Function* function = m_doc->function(m_matrixID);
×
496
        if (function != NULL)
×
497
        {
498
            qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
499
            adjustFunctionIntensity(function, pIntensity * intensity());
×
500
            if (value == 0 && !function->stopped())
×
501
            {
502
                function->stop(functionParent());
×
503
                resetIntensityOverrideAttribute();
×
504
            }
505
        }
506
    }
507
}
508

509
void VCMatrix::slotFunctionStopped()
×
510
{
511
    m_slider->blockSignals(true);
×
512
    m_slider->setValue(0);
×
513
    resetIntensityOverrideAttribute();
×
514
    m_slider->blockSignals(false);
×
515
}
×
516

517
void VCMatrix::slotFunctionChanged()
×
518
{
519
    m_updateTimer->start(UPDATE_TIMEOUT);
×
520
}
×
521

522
void VCMatrix::slotUpdate()
×
523
{
524
    if (m_matrixID == Function::invalidId())
×
525
        return;
×
526

527
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
528
    if (matrix == NULL)
×
529
        return;
×
530

531
    QColor startColor = matrix->startColor();
×
532
    QColor endColor = matrix->endColor();
×
533
    QString algorithmName;
×
534
    RGBAlgorithm::Type algorithmType = RGBAlgorithm::Plain;
×
535
    QHash<QString, QString> algorithmProperties;
×
536
    QString algorithmText;
×
537

538
    {
539
        QMutexLocker(&matrix->algorithmMutex());
×
540

541
        RGBAlgorithm* algo = matrix->algorithm();
×
542
        if (algo != NULL)
×
543
        {
544
            algorithmName = algo->name();
×
545
            algorithmType = algo->type();
×
546
            if (algorithmType == RGBAlgorithm::Script)
×
547
            {
548
                algorithmProperties = reinterpret_cast<RGBScript*>(algo)->propertiesAsStrings();
×
549
            }
550
            else if (algorithmType == RGBAlgorithm::Text)
×
551
            {
552
                algorithmText = reinterpret_cast<RGBText*>(algo)->text();
×
553
            }
554
        }
555
    }
556

557
    // Start / End color buttons
558
    QPixmap px(42, 42);
×
559
    px.fill(startColor);
×
560
    m_startColorButton->setIcon(px);
×
561
    slotSetStartColor(startColor);
×
562

563
    if (endColor == QColor())
×
564
        px.fill(Qt::transparent);
×
565
    else
566
        px.fill(endColor);
×
567
    m_endColorButton->setIcon(px);
×
568
    slotSetEndColor(endColor);
×
569

570
    // Algo combo box
571
    if (algorithmName != QString())
×
572
    {
573
        m_presetCombo->blockSignals(true);
×
574
        m_presetCombo->setCurrentText(algorithmName);
×
575
        m_presetCombo->blockSignals(false);
×
576
    }
577

578
    // Custom Buttons
579
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
580
            it != m_controls.end(); ++it)
×
581
    {
582
        QWidget* widget = it.key();
×
583
        VCMatrixControl* control = it.value();
×
584

585
        if (control->m_type == VCMatrixControl::StartColorKnob)
×
586
        {
587
            KnobWidget* knob = reinterpret_cast<KnobWidget*>(widget);
×
588
            knob->blockSignals(true);
×
589
            knob->setValue(control->rgbToValue(startColor.rgb()));            
×
UNCOV
590
            knob->blockSignals(false);
×
591
        }
592
        else if (control->m_type == VCMatrixControl::EndColorKnob)
×
593
        {
594
            KnobWidget* knob = reinterpret_cast<KnobWidget*>(widget);
×
595
            knob->blockSignals(true);
×
596
            knob->setValue(control->rgbToValue(endColor.rgb()));
×
UNCOV
597
            knob->blockSignals(false);
×
598
        }
599
        else if (control->m_type == VCMatrixControl::StartColor)
×
600
        {
601
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
602
            button->setDown(startColor == control->m_color);
×
603
        }
604
        else if (control->m_type == VCMatrixControl::EndColor)
×
605
        {
606
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
607
            button->setDown(endColor == control->m_color);
×
608
        }
609
        else if (control->m_type == VCMatrixControl::Animation)
×
610
        {
611
            bool on = false;
×
612
            if (algorithmType == RGBAlgorithm::Script)
×
613
            {
614
                if (algorithmName == control->m_resource)
×
615
                {
616
                    on = true;
×
617
                    for (QHash<QString, QString>::const_iterator it = control->m_properties.begin();
×
618
                            it != control->m_properties.end(); ++it)
×
619
                    {
620
                        if (algorithmProperties.value(it.key(), QString()) != it.value())
×
621
                            on = false;
×
622
                    }
623
                }
624
            }
625
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
626
            button->setDown(on);
×
627
        }
628
        else if (control->m_type == VCMatrixControl::Text)
×
629
        {
630
            bool on = false;
×
631
            if (algorithmType == RGBAlgorithm::Text)
×
632
            {
633
                if (algorithmText == control->m_resource)
×
634
                {
635
                    on = true;
×
636
                }
637
            }
638
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
639
            button->setDown(on);
×
640
        }
641
    }
642

643
    updateFeedback();
×
644
}
645

646
FunctionParent VCMatrix::functionParent() const
×
647
{
648
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
649
}
650

651
/*********************************************************************
652
 * Instant changes apply
653
 *********************************************************************/
654

655
void VCMatrix::setInstantChanges(bool instantly)
×
656
{
657
    m_instantApply = instantly;
×
658
}
×
659

660
bool VCMatrix::instantChanges() const
×
661
{
662
    return m_instantApply;
×
663
}
664

665
/*********************************************************************
666
 * Custom controls
667
 *********************************************************************/
668

669
void VCMatrix::addCustomControl(VCMatrixControl const& control)
×
670
{
671
    QWidget *controlWidget = NULL;
×
672

673
    if (control.m_type == VCMatrixControl::StartColor)
×
674
    {
675
        QPushButton *controlButton = new QPushButton(this);
×
676
        controlWidget = controlButton;
×
677
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
678
        controlButton->setFixedWidth(36);
×
679
        controlButton->setFocusPolicy(Qt::TabFocus);
×
680
        controlButton->setText("S");
×
681
    }
682
    else if (control.m_type == VCMatrixControl::EndColor)
×
683
    {
684
        QPushButton *controlButton = new QPushButton(this);
×
685
        controlWidget = controlButton;
×
686
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
687
        controlButton->setFixedWidth(36);
×
688
        controlButton->setFocusPolicy(Qt::TabFocus);
×
689
        controlButton->setText("E");
×
690
    }
691
    else if (control.m_type == VCMatrixControl::ResetEndColor)
×
692
    {
693
        QPushButton *controlButton = new QPushButton(this);
×
694
        controlWidget = controlButton;
×
695
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
696
        controlButton->setMinimumWidth(36);
×
697
        controlButton->setMaximumWidth(80);
×
698
        controlButton->setFocusPolicy(Qt::TabFocus);
×
699
        QString btnLabel = tr("End Color Reset");
×
700
        controlButton->setToolTip(btnLabel);
×
701
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
702
    }
703
    else if (control.m_type == VCMatrixControl::Animation ||
×
704
             control.m_type == VCMatrixControl::Text)
×
705
    {
706
        QPushButton *controlButton = new QPushButton(this);
×
707
        controlWidget = controlButton;
×
708
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
709
        controlButton->setMinimumWidth(36);
×
710
        controlButton->setMaximumWidth(80);
×
711
        controlButton->setFocusPolicy(Qt::TabFocus);
×
712
        QString btnLabel = control.m_resource;
×
713
        if (!control.m_properties.isEmpty())
×
714
        {
715
            btnLabel += " (";
×
716
            QHashIterator<QString, QString> it(control.m_properties);
×
717
            while(it.hasNext())
×
718
            {
719
                it.next();
×
720
                btnLabel += it.value();
×
721
                if (it.hasNext())
×
722
                    btnLabel += ",";
×
723
            }
724
            btnLabel += ")";
×
725
        }
726
        controlButton->setToolTip(btnLabel);
×
727
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
728
    }
729
    else if (control.m_type == VCMatrixControl::StartColorKnob)
×
730
    {
731
        KnobWidget *controlKnob = new KnobWidget(this);
×
732
        controlWidget = controlKnob;
×
733
        controlKnob->setColor(control.m_color);
×
734
        controlKnob->setFixedWidth(36);
×
735
        controlKnob->setFixedHeight(36);
×
736
        QString knobLabel;
×
737
        if (control.m_color == Qt::red)
×
738
            knobLabel = tr("Start color Red component");
×
739
        else if (control.m_color == Qt::green)
×
740
            knobLabel = tr("Start color Green component");
×
741
        else if (control.m_color == Qt::blue)
×
742
            knobLabel = tr("Start color Blue component");
×
743
        controlKnob->setToolTip(knobLabel);
×
744
    }
745
    else if (control.m_type == VCMatrixControl::EndColorKnob)
×
746
    {
747
        KnobWidget *controlKnob = new KnobWidget(this);
×
748
        controlWidget = controlKnob;
×
749
        controlKnob->setColor(control.m_color.darker(250));
×
750
        controlKnob->setFixedWidth(36);
×
751
        controlKnob->setFixedHeight(36);
×
752
        QString knobLabel;
×
753
        if (control.m_color == Qt::red)
×
754
            knobLabel = tr("End color Red component");
×
755
        else if (control.m_color == Qt::green)
×
756
            knobLabel = tr("End color Green component");
×
757
        else if (control.m_color == Qt::blue)
×
758
            knobLabel = tr("End color Blue component");
×
759
        controlKnob->setToolTip(knobLabel);
×
760
    }
761

762
    Q_ASSERT(controlWidget != NULL);
×
763

764
    if (control.widgetType() == VCMatrixControl::Knob)
×
765
    {
766
        connect(reinterpret_cast<KnobWidget*>(controlWidget), SIGNAL(valueChanged(int)),
×
767
                this, SLOT(slotCustomControlValueChanged()));
768
    }
769
    else
770
    {
771
        connect(reinterpret_cast<QPushButton*>(controlWidget), SIGNAL(clicked()),
×
772
                this, SLOT(slotCustomControlClicked()));
773
    }
774

775

776
    if (mode() == Doc::Design)
×
777
        controlWidget->setEnabled(false);
×
778

779
    VCMatrixControl *c_control = new VCMatrixControl(control);
×
780
    m_controls[controlWidget] = c_control;
×
781
    m_widgets[c_control] = controlWidget;
×
782

783
    m_controlsLayout->addWidget(controlWidget);
×
784

785
    if (m_controls[controlWidget]->m_inputSource != NULL)
×
786
    {
787
        setInputSource(m_controls[controlWidget]->m_inputSource, m_controls[controlWidget]->m_id);
×
788
    }
789

790
    slotFunctionChanged(); // Start update timer
×
791
}
×
792

793
void VCMatrix::resetCustomControls()
×
794
{
795
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
796
            it != m_controls.end(); ++it)
×
797
    {
798
        QWidget* widget = it.key();
×
799
        m_controlsLayout->removeWidget(widget);
×
800
        delete widget;
×
801

802
        VCMatrixControl* control = it.value();
×
803
        if (!control->m_inputSource.isNull())
×
804
            setInputSource(QSharedPointer<QLCInputSource>(), control->m_id);
×
805
        delete control;
×
806
    }
807
    m_controls.clear();
×
808
    m_widgets.clear();
×
809
}
×
810

811
QList<VCMatrixControl *> VCMatrix::customControls() const
×
812
{
813
    QList<VCMatrixControl*> controls = m_controls.values();
×
814
    std::sort(controls.begin(), controls.end(), VCMatrixControl::compare);
×
815
    return controls;
×
816
}
817

818
QWidget *VCMatrix::getWidget(VCMatrixControl* control) const
×
819
{
820
    return m_widgets[control];
×
821
}
822

823
void VCMatrix::slotCustomControlClicked()
×
824
{
825
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
×
826
    VCMatrixControl *control = m_controls[btn];
×
827
    if (control != NULL)
×
828
    {
829
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
830
        if (matrix == NULL || mode() == Doc::Design)
×
831
            return;
×
832

833
        if (control->m_type == VCMatrixControl::StartColor)
×
834
        {
835
            matrix->setStartColor(control->m_color);
×
836
            if (instantChanges() == true)
×
837
                matrix->updateColorDelta();
×
838
            btn->setDown(true);
×
NEW
839
            emit startColorChanged();
×
840
        }
841
        else if (control->m_type == VCMatrixControl::EndColor)
×
842
        {
843
            matrix->setEndColor(control->m_color);
×
844
            if (instantChanges() == true)
×
845
                matrix->updateColorDelta();
×
846
            btn->setDown(true);
×
NEW
847
            emit endColorChanged();
×
848
        }
849
        else if (control->m_type == VCMatrixControl::ResetEndColor)
×
850
        {
851
            matrix->setEndColor(QColor());
×
852
            if (instantChanges() == true)
×
853
                matrix->updateColorDelta();
×
NEW
854
            emit endColorChanged();
×
855
        }
856
        else if (control->m_type == VCMatrixControl::Animation)
×
857
        {
858
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, control->m_resource);
×
859
            if (!control->m_properties.isEmpty())
×
860
            {
861
                RGBScript *script = static_cast<RGBScript*> (algo);
×
862
                QHashIterator<QString, QString> it(control->m_properties);
×
863
                while(it.hasNext())
×
864
                {
865
                    it.next();
×
866
                    script->setProperty(it.key(), it.value());
×
867
                    matrix->setProperty(it.key(), it.value());
×
868
                }
869
            }
870
            matrix->setAlgorithm(algo);
×
871
            if (instantChanges() == true)
×
872
                matrix->updateColorDelta();
×
873
            btn->setDown(true);
×
874
        }
875
        else if (control->m_type == VCMatrixControl::Text)
×
876
        {
877
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, "Text");
×
878
            RGBText* text = static_cast<RGBText*> (algo);
×
879
            text->setText(control->m_resource);
×
880
            matrix->setAlgorithm(algo);
×
881
            if (instantChanges() == true)
×
882
                matrix->updateColorDelta();
×
883
            btn->setDown(true);
×
884
        }
885
    }
886
}
887

888
void VCMatrix::slotCustomControlValueChanged()
×
889
{
890
    KnobWidget *knob = qobject_cast<KnobWidget*>(sender());
×
891
    VCMatrixControl *control = m_controls[knob];
×
892
    if (control != NULL)
×
893
    {
894
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
895
        if (matrix == NULL || mode() == Doc::Design)
×
896
            return;
×
897

898
        if (control->m_type == VCMatrixControl::StartColorKnob)
×
899
        {
900
            QRgb color = matrix->startColor().rgb();
×
901
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
902
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
903

904
            matrix->setStartColor(color);
×
905
            if (instantChanges() == true)
×
906
                matrix->updateColorDelta();
×
907
        }
908
        else if (control->m_type == VCMatrixControl::EndColorKnob)
×
909
        {
910
            QRgb color = matrix->endColor().rgb();
×
911
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
912
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
913

914
            matrix->setEndColor(color);
×
915
            if (instantChanges() == true)
×
916
                matrix->updateColorDelta();
×
917
        }
918
        else
919
        {
920
            // We are not supposed to be here
921
            Q_ASSERT(false);
×
922
        }
NEW
923
        emit matrixControlKnobValueChanged(control->m_id, knob->value());
×
924
    }
925
}
926

NEW
927
void VCMatrix::slotMatrixControlKnobValueChanged(int controlID, int value)
×
928
{
NEW
929
    QList<VCMatrixControl *> customControls = this->customControls();
×
NEW
930
    for (int i = 0; i < customControls.length(); i++)
×
931
    {
NEW
932
        if (customControls[i]->m_id == controlID)
×
933
        {
NEW
934
            if (customControls[i]->m_type == VCMatrixControl::StartColorKnob || customControls[i]->m_type == VCMatrixControl::EndColorKnob)
×
935
            {
NEW
936
                KnobWidget *knob = qobject_cast<KnobWidget*>(this->getWidget(customControls[i]));
×
NEW
937
                knob->blockSignals(true);
×
NEW
938
                knob->setValue(value);
×
NEW
939
                knob->blockSignals(false);
×
NEW
940
                break;
×
941
            }
942
        }
943
    }
NEW
944
}
×
945

NEW
946
void VCMatrix::slotMatrixControlPushButtonClicked(int controlID)
×
947
{
NEW
948
    QList<VCMatrixControl *> customControls = this->customControls();
×
NEW
949
    for (int i = 0; i < customControls.length(); i++)
×
950
    {
NEW
951
        if (customControls[i]->m_id == controlID)
×
952
        {
NEW
953
            QPushButton *btn = qobject_cast<QPushButton*>(this->getWidget(customControls[i]));
×
NEW
954
            btn->click();
×
NEW
955
            break;
×
956
        }
957
    }
UNCOV
958
}
×
959

960
void VCMatrix::slotModeChanged(Doc::Mode mode)
×
961
{
962
    if (mode == Doc::Operate)
×
963
        enableWidgetUI(true);
×
964
    else
965
        enableWidgetUI(false);
×
966

967
    VCWidget::slotModeChanged(mode);
×
968
}
×
969

970
/*********************************************************************
971
 * External input
972
 *********************************************************************/
973

974
void VCMatrix::slotKeyPressed(const QKeySequence &keySequence)
×
975
{
976
    if (acceptsInput() == false)
×
977
        return;
×
978

979
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
980
            it != m_controls.end(); ++it)
×
981
    {
982
        VCMatrixControl *control = it.value();
×
983
        if (control->m_keySequence == keySequence &&
×
984
                control->widgetType() == VCMatrixControl::Button) // Only for buttons
×
985
        {
986
            QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
987
            button->click();
×
988
        }
989
    }
990
}
991

992
void VCMatrix::updateFeedback()
×
993
{
994
    sendFeedback(m_slider->value());
×
995

996
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
997
            it != m_controls.end(); ++it)
×
998
    {
999
        VCMatrixControl *control = it.value();
×
1000
        if (control->m_inputSource != NULL)
×
1001
        {
1002
            if (control->widgetType() == VCMatrixControl::Knob)
×
1003
            {
1004
                KnobWidget* knob = reinterpret_cast<KnobWidget*>(it.key());
×
1005
                sendFeedback(knob->value(), control->m_inputSource);
×
1006
            }
1007
            else // if (control->widgetType() == VCMatrixControl::Button)
1008
            {
1009
                QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
1010
                sendFeedback(button->isDown() ?
×
1011
                                 control->m_inputSource->upperValue() :
×
1012
                                 control->m_inputSource->lowerValue(),
×
1013
                                 control->m_inputSource);
×
1014
            }
1015
        }
1016
    }
1017
}
×
1018

1019
void VCMatrix::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
1020
{
1021
    /* Don't let input data through in design mode or if disabled */
1022
    if (acceptsInput() == false)
×
1023
        return;
×
1024

1025
    quint32 pagedCh = (page() << 16) | channel;
×
1026

1027
    if (checkInputSource(universe, pagedCh, value, sender()))
×
1028
    {
1029
        m_slider->setValue((int) value);
×
1030
        return;
×
1031
    }
1032

1033
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
1034
            it != m_controls.end(); ++it)
×
1035
    {
1036
        VCMatrixControl *control = it.value();
×
1037
        if (control->m_inputSource != NULL &&
×
1038
                control->m_inputSource->universe() == universe &&
×
1039
                control->m_inputSource->channel() == pagedCh)
×
1040
        {
1041
            if (control->widgetType() == VCMatrixControl::Knob)
×
1042
            {
1043
                KnobWidget* knob = reinterpret_cast<KnobWidget*>(it.key());
×
1044
                knob->setValue(value);
×
1045
            }
1046
            else
1047
            {
1048
                QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
1049
                button->click();
×
1050
            }
1051
        }
1052
    }
1053
}
1054

1055
bool VCMatrix::loadXML(QXmlStreamReader &root)
×
1056
{
1057
    QString str;
×
1058

1059
    if (root.name() != KXMLQLCVCMatrix)
×
1060
    {
1061
        qWarning() << Q_FUNC_INFO << "Matrix node not found";
×
1062
        return false;
×
1063
    }
1064

1065
    /* Widget commons */
1066
    loadXMLCommon(root);
×
1067

1068
    // Sorted list for new controls
1069
    QList<VCMatrixControl> newControls;
×
1070

1071
    /* Children */
1072
    while (root.readNextStartElement())
×
1073
    {
1074
        if (root.name() == KXMLQLCWindowState)
×
1075
        {
1076
            bool visible = false;
×
1077
            int x = 0, y = 0, w = 0, h = 0;
×
1078
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
×
1079
            setGeometry(x, y, w, h);
×
1080
        }
1081
        else if (root.name() == KXMLQLCVCWidgetAppearance)
×
1082
        {
1083
            loadXMLAppearance(root);
×
1084
        }
1085
        else if (root.name() == KXMLQLCVCMatrixFunction)
×
1086
        {
1087
            QXmlStreamAttributes attrs = root.attributes();
×
1088
            str = attrs.value(KXMLQLCVCMatrixFunctionID).toString();
×
1089
            setFunction(str.toUInt());
×
1090
            if (attrs.hasAttribute(KXMLQLCVCMatrixInstantApply))
×
1091
                setInstantChanges(true);
×
1092
            root.skipCurrentElement();
×
1093
        }
1094
        else if (root.name() == KXMLQLCVCWidgetInput)
×
1095
        {
1096
            loadXMLInput(root);
×
1097
        }
1098
        else if(root.name() == KXMLQLCVCMatrixControl)
×
1099
        {
1100
            VCMatrixControl control(0xff);
×
1101
            if (control.loadXML(root))
×
1102
                newControls.insert(std::lower_bound(newControls.begin(), newControls.end(), control), control);
×
1103
        }
1104
        else if (root.name() == KXMLQLCVCMatrixVisibilityMask)
×
1105
        {
1106
            setVisibilityMask(root.readElementText().toUInt());
×
1107
        }
1108
        else
1109
        {
1110
            qWarning() << Q_FUNC_INFO << "Unknown VCMatrix tag:" << root.name().toString();
×
1111
            root.skipCurrentElement();
×
1112
        }
1113
    }
1114

1115
    foreach (VCMatrixControl const& control, newControls)
×
1116
        addCustomControl(control);
×
1117

1118
    return true;
×
1119
}
1120

1121
bool VCMatrix::saveXML(QXmlStreamWriter *doc)
×
1122
{
1123
    Q_ASSERT(doc != NULL);
×
1124

1125
    /* VC button entry */
1126
    doc->writeStartElement(KXMLQLCVCMatrix);
×
1127

1128
    saveXMLCommon(doc);
×
1129

1130
    /* Window state */
1131
    saveXMLWindowState(doc);
×
1132

1133
    /* Appearance */
1134
    saveXMLAppearance(doc);
×
1135

1136
    /* Function */
1137
    doc->writeStartElement(KXMLQLCVCMatrixFunction);
×
1138
    doc->writeAttribute(KXMLQLCVCMatrixFunctionID, QString::number(function()));
×
1139

1140
    if (instantChanges() == true)
×
1141
        doc->writeAttribute(KXMLQLCVCMatrixInstantApply, "true");
×
1142
    doc->writeEndElement();
×
1143

1144
    /* Default controls visibility  */
1145
    if (m_visibilityMask != VCMatrix::defaultVisibilityMask())
×
1146
        doc->writeTextElement(KXMLQLCVCMatrixVisibilityMask, QString::number(m_visibilityMask));
×
1147

1148
    /* Slider External input */
1149
    saveXMLInput(doc);
×
1150

1151
    foreach(VCMatrixControl *control, customControls())
×
1152
        control->saveXML(doc);
×
1153

1154
    /* End the <Matrix> tag */
1155
    doc->writeEndElement();
×
1156

1157
    return true;
×
1158
}
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