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

mcallegari / qlcplus / 6915196025

18 Nov 2023 05:02PM UTC coverage: 32.013% (-0.006%) from 32.019%
6915196025

push

github

mcallegari
vc/animation: start to fix #1482 mess

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

3 existing lines in 1 file now uncovered.

15109 of 47197 relevant lines covered (32.01%)

23539.95 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);
×
UNCOV
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);
×
UNCOV
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
    emit sliderValueChanged(value);
×
248

249
    Function* function = m_doc->function(m_matrixID);
×
250
    if (function == NULL || mode() == Doc::Design)
×
251
        return;
×
252

253
    if (m_sliderExternalMovement)
×
254
        return;
×
255

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

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

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

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

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

NEW
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
{
NEW
325
    RGBMatrix *matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
NEW
326
    if (matrix == NULL)
×
NEW
327
        return;
×
328

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

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

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

645
    updateFeedback();
×
646
}
647

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

653
/*********************************************************************
654
 * Instant changes apply
655
 *********************************************************************/
656

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

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

667
/*********************************************************************
668
 * Custom controls
669
 *********************************************************************/
670

671
void VCMatrix::slotMatrixControlKnobValueChanged(int controlID, int value)
×
672
{
673
    QList<VCMatrixControl *> customControls = this->customControls();
×
NEW
674
    for (int i = 0; i < customControls.length(); i++)
×
675
    {
NEW
676
        if (customControls[i]->m_id == controlID)
×
677
        {
NEW
678
            if (customControls[i]->m_type == VCMatrixControl::StartColorKnob || customControls[i]->m_type == VCMatrixControl::EndColorKnob)
×
679
            {
680
                KnobWidget *knob = qobject_cast<KnobWidget*>(this->getWidget(customControls[i]));
×
NEW
681
                knob->blockSignals(true);
×
682
                knob->setValue(value);
×
NEW
683
                knob->blockSignals(false);
×
UNCOV
684
                break;
×
685
            }
686
        }
687
    }
688
}
×
689

690
void VCMatrix::slotMatrixControlPushButtonClicked(int controlID)
×
691
{
692
    QList<VCMatrixControl *> customControls = this->customControls();
×
NEW
693
    for (int i = 0; i < customControls.length(); i++)
×
694
    {
NEW
695
        if (customControls[i]->m_id == controlID)
×
696
        {
NEW
697
            QPushButton *btn = qobject_cast<QPushButton*>(this->getWidget(customControls[i]));
×
698
            emit btn->clicked();
×
699
            break;
×
700
        }
701
    }
702
}
×
703

704
void VCMatrix::addCustomControl(VCMatrixControl const& control)
×
705
{
706
    QWidget *controlWidget = NULL;
×
707

708
    if (control.m_type == VCMatrixControl::StartColor)
×
709
    {
710
        QPushButton *controlButton = new QPushButton(this);
×
711
        controlWidget = controlButton;
×
712
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
713
        controlButton->setFixedWidth(36);
×
714
        controlButton->setFocusPolicy(Qt::TabFocus);
×
715
        controlButton->setText("S");
×
716
    }
717
    else if (control.m_type == VCMatrixControl::EndColor)
×
718
    {
719
        QPushButton *controlButton = new QPushButton(this);
×
720
        controlWidget = controlButton;
×
721
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
722
        controlButton->setFixedWidth(36);
×
723
        controlButton->setFocusPolicy(Qt::TabFocus);
×
724
        controlButton->setText("E");
×
725
    }
726
    else if (control.m_type == VCMatrixControl::ResetEndColor)
×
727
    {
728
        QPushButton *controlButton = new QPushButton(this);
×
729
        controlWidget = controlButton;
×
730
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
731
        controlButton->setMinimumWidth(36);
×
732
        controlButton->setMaximumWidth(80);
×
733
        controlButton->setFocusPolicy(Qt::TabFocus);
×
734
        QString btnLabel = tr("End Color Reset");
×
735
        controlButton->setToolTip(btnLabel);
×
736
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
737
    }
738
    else if (control.m_type == VCMatrixControl::Animation ||
×
739
             control.m_type == VCMatrixControl::Text)
×
740
    {
741
        QPushButton *controlButton = new QPushButton(this);
×
742
        controlWidget = controlButton;
×
743
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
744
        controlButton->setMinimumWidth(36);
×
745
        controlButton->setMaximumWidth(80);
×
746
        controlButton->setFocusPolicy(Qt::TabFocus);
×
747
        QString btnLabel = control.m_resource;
×
748
        if (!control.m_properties.isEmpty())
×
749
        {
750
            btnLabel += " (";
×
751
            QHashIterator<QString, QString> it(control.m_properties);
×
752
            while(it.hasNext())
×
753
            {
754
                it.next();
×
755
                btnLabel += it.value();
×
756
                if (it.hasNext())
×
757
                    btnLabel += ",";
×
758
            }
759
            btnLabel += ")";
×
760
        }
761
        controlButton->setToolTip(btnLabel);
×
762
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
763
    }
764
    else if (control.m_type == VCMatrixControl::StartColorKnob)
×
765
    {
766
        KnobWidget *controlKnob = new KnobWidget(this);
×
767
        controlWidget = controlKnob;
×
768
        controlKnob->setColor(control.m_color);
×
769
        controlKnob->setFixedWidth(36);
×
770
        controlKnob->setFixedHeight(36);
×
771
        QString knobLabel;
×
772
        if (control.m_color == Qt::red)
×
773
            knobLabel = tr("Start color Red component");
×
774
        else if (control.m_color == Qt::green)
×
775
            knobLabel = tr("Start color Green component");
×
776
        else if (control.m_color == Qt::blue)
×
777
            knobLabel = tr("Start color Blue component");
×
778
        controlKnob->setToolTip(knobLabel);
×
779
    }
780
    else if (control.m_type == VCMatrixControl::EndColorKnob)
×
781
    {
782
        KnobWidget *controlKnob = new KnobWidget(this);
×
783
        controlWidget = controlKnob;
×
784
        controlKnob->setColor(control.m_color.darker(250));
×
785
        controlKnob->setFixedWidth(36);
×
786
        controlKnob->setFixedHeight(36);
×
787
        QString knobLabel;
×
788
        if (control.m_color == Qt::red)
×
789
            knobLabel = tr("End color Red component");
×
790
        else if (control.m_color == Qt::green)
×
791
            knobLabel = tr("End color Green component");
×
792
        else if (control.m_color == Qt::blue)
×
793
            knobLabel = tr("End color Blue component");
×
794
        controlKnob->setToolTip(knobLabel);
×
795
    }
796

797
    Q_ASSERT(controlWidget != NULL);
×
798

799
    if (control.widgetType() == VCMatrixControl::Knob)
×
800
    {
801
        connect(reinterpret_cast<KnobWidget*>(controlWidget), SIGNAL(valueChanged(int)),
×
802
                this, SLOT(slotCustomControlValueChanged()));
803
    }
804
    else
805
    {
806
        connect(reinterpret_cast<QPushButton*>(controlWidget), SIGNAL(clicked()),
×
807
                this, SLOT(slotCustomControlClicked()));
808
    }
809

810

811
    if (mode() == Doc::Design)
×
812
        controlWidget->setEnabled(false);
×
813

814
    VCMatrixControl *c_control = new VCMatrixControl(control);
×
815
    m_controls[controlWidget] = c_control;
×
816
    m_widgets[c_control] = controlWidget;
×
817

818
    m_controlsLayout->addWidget(controlWidget);
×
819

820
    if (m_controls[controlWidget]->m_inputSource != NULL)
×
821
    {
822
        setInputSource(m_controls[controlWidget]->m_inputSource, m_controls[controlWidget]->m_id);
×
823
    }
824

825
    slotFunctionChanged(); // Start update timer
×
826
}
×
827

828
void VCMatrix::resetCustomControls()
×
829
{
830
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
831
            it != m_controls.end(); ++it)
×
832
    {
833
        QWidget* widget = it.key();
×
834
        m_controlsLayout->removeWidget(widget);
×
835
        delete widget;
×
836

837
        VCMatrixControl* control = it.value();
×
838
        if (!control->m_inputSource.isNull())
×
839
            setInputSource(QSharedPointer<QLCInputSource>(), control->m_id);
×
840
        delete control;
×
841
    }
842
    m_controls.clear();
×
843
    m_widgets.clear();
×
844
}
×
845

846
QList<VCMatrixControl *> VCMatrix::customControls() const
×
847
{
848
    QList<VCMatrixControl*> controls = m_controls.values();
×
849
    std::sort(controls.begin(), controls.end(), VCMatrixControl::compare);
×
850
    return controls;
×
851
}
852

853
QWidget *VCMatrix::getWidget(VCMatrixControl* control) const
×
854
{
855
    return m_widgets[control];
×
856
}
857

858
void VCMatrix::slotCustomControlClicked()
×
859
{
860
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
×
861
    VCMatrixControl *control = m_controls[btn];
×
862
    if (control != NULL)
×
863
    {
864
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
865
        if (matrix == NULL || mode() == Doc::Design)
×
866
            return;
×
867

868
        if (control->m_type == VCMatrixControl::StartColor)
×
869
        {
870
            matrix->setStartColor(control->m_color);
×
871
            if (instantChanges() == true)
×
872
                matrix->updateColorDelta();
×
873
            btn->setDown(true);
×
874
        }
875
        else if (control->m_type == VCMatrixControl::EndColor)
×
876
        {
877
            matrix->setEndColor(control->m_color);
×
878
            if (instantChanges() == true)
×
879
                matrix->updateColorDelta();
×
880
            btn->setDown(true);
×
881
        }
882
        else if (control->m_type == VCMatrixControl::ResetEndColor)
×
883
        {
884
            matrix->setEndColor(QColor());
×
885
            if (instantChanges() == true)
×
886
                matrix->updateColorDelta();
×
887
        }
888
        else if (control->m_type == VCMatrixControl::Animation)
×
889
        {
890
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, control->m_resource);
×
891
            if (!control->m_properties.isEmpty())
×
892
            {
893
                RGBScript *script = static_cast<RGBScript*> (algo);
×
894
                QHashIterator<QString, QString> it(control->m_properties);
×
895
                while(it.hasNext())
×
896
                {
897
                    it.next();
×
898
                    script->setProperty(it.key(), it.value());
×
899
                    matrix->setProperty(it.key(), it.value());
×
900
                }
901
            }
902
            matrix->setAlgorithm(algo);
×
903
            if (instantChanges() == true)
×
904
                matrix->updateColorDelta();
×
905
            btn->setDown(true);
×
906
        }
907
        else if (control->m_type == VCMatrixControl::Text)
×
908
        {
909
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, "Text");
×
910
            RGBText* text = static_cast<RGBText*> (algo);
×
911
            text->setText(control->m_resource);
×
912
            matrix->setAlgorithm(algo);
×
913
            if (instantChanges() == true)
×
914
                matrix->updateColorDelta();
×
915
            btn->setDown(true);
×
916
        }
917
    }
918
}
919

920
void VCMatrix::slotCustomControlValueChanged()
×
921
{
922
    KnobWidget *knob = qobject_cast<KnobWidget*>(sender());
×
923
    VCMatrixControl *control = m_controls[knob];
×
924
    if (control != NULL)
×
925
    {
926
        emit matrixControlKnobValueChanged(control->m_id, knob->value());
×
927
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
928
        if (matrix == NULL || mode() == Doc::Design)
×
929
            return;
×
930

931
        if (control->m_type == VCMatrixControl::StartColorKnob)
×
932
        {
933
            QRgb color = matrix->startColor().rgb();
×
934
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
935
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
936

937
            matrix->setStartColor(color);
×
938
            if (instantChanges() == true)
×
939
                matrix->updateColorDelta();
×
940
        }
941
        else if (control->m_type == VCMatrixControl::EndColorKnob)
×
942
        {
943
            QRgb color = matrix->endColor().rgb();
×
944
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
945
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
946

947
            matrix->setEndColor(color);
×
948
            if (instantChanges() == true)
×
949
                matrix->updateColorDelta();
×
950
        }
951
        else
952
        {
953
            // We are not supposed to be here
954
            Q_ASSERT(false);
×
955
        }
956
    }
957
}
958

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

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

969
/*********************************************************************
970
 * External input
971
 *********************************************************************/
972

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1117
    return true;
×
1118
}
1119

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

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

1127
    saveXMLCommon(doc);
×
1128

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

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

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

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

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

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

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

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

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