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

mcallegari / qlcplus / 6683238402

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

push

github

mcallegari
engine: fix build

15385 of 54809 relevant lines covered (28.07%)

20267.63 hits per line

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

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::slotSliderMoved(int value)
×
240
{
241
    Function* function = m_doc->function(m_matrixID);
×
242
    if (function == NULL || mode() == Doc::Design)
×
243
        return;
×
244

245
    if (m_sliderExternalMovement)
×
246
        return;
×
247

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

271
void VCMatrix::slotStartColorChanged(QRgb color)
×
272
{
273
    QColor col(color);
×
274
    QPixmap px(42, 42);
×
275
    px.fill(col);
×
276
    m_startColorButton->setIcon(px);
×
277

278
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
279
    if (matrix == NULL || mode() == Doc::Design)
×
280
        return;
×
281

282
    matrix->setStartColor(col);
×
283
    if (instantChanges() == true)
×
284
        matrix->updateColorDelta();
×
285
}
286

287
void VCMatrix::slotEndColorChanged(QRgb color)
×
288
{
289
    QColor col(color);
×
290
    QPixmap px(42, 42);
×
291
    px.fill(col);
×
292
    m_endColorButton->setIcon(px);
×
293

294
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
295
    if (matrix == NULL || mode() == Doc::Design)
×
296
        return;
×
297

298
    matrix->setEndColor(col);
×
299
    if (instantChanges() == true)
×
300
        matrix->updateColorDelta();
×
301
}
302

303
void VCMatrix::slotAnimationChanged(QString name)
×
304
{
305
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
306
    if (matrix == NULL || mode() == Doc::Design)
×
307
        return;
×
308

309
    RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, name);
×
310
    matrix->setAlgorithm(algo);
×
311
    if (instantChanges() == true)
×
312
        matrix->updateColorDelta();
×
313
}
314

315
void VCMatrix::setVisibilityMask(quint32 mask)
×
316
{
317
    if (mask & ShowSlider) m_slider->show();
×
318
    else m_slider->hide();
×
319

320
    if (mask & ShowLabel) m_label->show();
×
321
    else m_label->hide();
×
322

323
    if (mask & ShowStartColorButton) m_startColorButton->show();
×
324
    else m_startColorButton->hide();
×
325

326
    if (mask & ShowEndColorButton) m_endColorButton->show();
×
327
    else m_endColorButton->hide();
×
328

329
    if (mask & ShowPresetCombo) m_presetCombo->show();
×
330
    else m_presetCombo->hide();
×
331

332
    m_visibilityMask = mask;
×
333
}
×
334

335
quint32 VCMatrix::visibilityMask() const
×
336
{
337
    return m_visibilityMask;
×
338
}
339

340
quint32 VCMatrix::defaultVisibilityMask()
×
341
{
342
    return ShowSlider
343
        | ShowLabel
344
        | ShowStartColorButton
345
        | ShowEndColorButton
346
        | ShowPresetCombo
×
347
        ;
348
}
349

350
/*********************************************************************
351
 * Properties
352
 *********************************************************************/
353

354
void VCMatrix::editProperties()
×
355
{
356
    VCMatrixProperties prop(this, m_doc);
×
357
    if (prop.exec() == QDialog::Accepted)
×
358
        m_doc->setModified();
×
359
}
×
360

361
/*************************************************************************
362
 * VCWidget-inherited
363
 *************************************************************************/
364

365
void VCMatrix::adjustIntensity(qreal val)
×
366
{
367
    VCWidget::adjustIntensity(val);
×
368
    this->slotSliderMoved(this->m_slider->value());
×
369
}
×
370

371
/*********************************************************************
372
 * Function attachment
373
 *********************************************************************/
374

375
void VCMatrix::setFunction(quint32 id)
×
376
{
377
    Function *old = m_doc->function(m_matrixID);
×
378
    if (old != NULL)
×
379
    {
380
        disconnect(old, SIGNAL(stopped(quint32)),
×
381
                this, SLOT(slotFunctionStopped()));
382
        disconnect(old, SIGNAL(changed(quint32)),
×
383
                this, SLOT(slotFunctionChanged()));
384
    }
385

386
    RGBMatrix* matrix = qobject_cast<RGBMatrix*> (m_doc->function(id));
×
387

388
    if (matrix == NULL)
×
389
        m_matrixID = Function::invalidId();
×
390
    else
391
    {
392
        m_matrixID = id;
×
393
        connect(matrix, SIGNAL(stopped(quint32)),
×
394
                this, SLOT(slotFunctionStopped()));
395
        connect(matrix, SIGNAL(changed(quint32)),
×
396
                this, SLOT(slotFunctionChanged()));
397
    }
398

399
    slotUpdate();
×
400
}
×
401

402
quint32 VCMatrix::function() const
×
403
{
404
    return m_matrixID;
×
405
}
406

407
void VCMatrix::notifyFunctionStarting(quint32 fid, qreal functionIntensity)
×
408
{
409
    if (mode() == Doc::Design)
×
410
        return;
×
411

412
    if (fid == m_matrixID)
×
413
        return;
×
414

415
    int value = SCALE(1.0 - functionIntensity,
×
416
            0, 1.0,
417
            m_slider->minimum(), m_slider->maximum());
418
    if (m_slider->value() > value)
×
419
    {
420
        m_sliderExternalMovement = true;
×
421
        m_slider->setValue(value);
×
422
        m_sliderExternalMovement = false;
×
423

424
        Function* function = m_doc->function(m_matrixID);
×
425
        if (function != NULL)
×
426
        {
427
            qreal pIntensity = qreal(value) / qreal(UCHAR_MAX);
×
428
            adjustFunctionIntensity(function, pIntensity * intensity());
×
429
            if (value == 0 && !function->stopped())
×
430
            {
431
                function->stop(functionParent());
×
432
                resetIntensityOverrideAttribute();
×
433
            }
434
        }
435
    }
436
}
437

438
void VCMatrix::slotFunctionStopped()
×
439
{
440
    m_slider->blockSignals(true);
×
441
    m_slider->setValue(0);
×
442
    resetIntensityOverrideAttribute();
×
443
    m_slider->blockSignals(false);
×
444
}
×
445

446
void VCMatrix::slotFunctionChanged()
×
447
{
448
    m_updateTimer->start(UPDATE_TIMEOUT);
×
449
}
×
450

451
void VCMatrix::slotUpdate()
×
452
{
453
    if (m_matrixID == Function::invalidId())
×
454
        return;
×
455

456
    RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
457
    if (matrix == NULL)
×
458
        return;
×
459

460
    QColor startColor = matrix->startColor();
×
461
    QColor endColor = matrix->endColor();
×
462
    QString algorithmName;
×
463
    RGBAlgorithm::Type algorithmType = RGBAlgorithm::Plain;
×
464
    QHash<QString, QString> algorithmProperties;
×
465
    QString algorithmText;
×
466

467
    {
468
        QMutexLocker(&matrix->algorithmMutex());
×
469

470
        RGBAlgorithm* algo = matrix->algorithm();
×
471
        if (algo != NULL)
×
472
        {
473
            algorithmName = algo->name();
×
474
            algorithmType = algo->type();
×
475
            if (algorithmType == RGBAlgorithm::Script)
×
476
            {
477
                algorithmProperties = reinterpret_cast<RGBScript*>(algo)->propertiesAsStrings();
×
478
            }
479
            else if (algorithmType == RGBAlgorithm::Text)
×
480
            {
481
                algorithmText = reinterpret_cast<RGBText*>(algo)->text();
×
482
            }
483
        }
484
    }
485

486
    // Start / End color buttons
487
    QPixmap px(42, 42);
×
488
    px.fill(startColor);
×
489
    m_startColorButton->setIcon(px);
×
490
    if (endColor == QColor())
×
491
        px.fill(Qt::transparent);
×
492
    else
493
        px.fill(endColor);
×
494
    m_endColorButton->setIcon(px);
×
495

496
    // Algo combo box
497
    if (algorithmName != QString())
×
498
    {
499
        m_presetCombo->blockSignals(true);
×
500
        m_presetCombo->setCurrentText(algorithmName);
×
501
        m_presetCombo->blockSignals(false);
×
502
    }
503

504
    // Custom Buttons
505
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
506
            it != m_controls.end(); ++it)
×
507
    {
508
        QWidget* widget = it.key();
×
509
        VCMatrixControl* control = it.value();
×
510

511
        if (control->m_type == VCMatrixControl::StartColorKnob)
×
512
        {
513
            KnobWidget* knob = reinterpret_cast<KnobWidget*>(widget);
×
514
            knob->blockSignals(true);
×
515
            knob->setValue(control->rgbToValue(startColor.rgb()));
×
516
            knob->blockSignals(false);
×
517
        }
518
        else if (control->m_type == VCMatrixControl::EndColorKnob)
×
519
        {
520
            KnobWidget* knob = reinterpret_cast<KnobWidget*>(widget);
×
521
            knob->blockSignals(true);
×
522
            knob->setValue(control->rgbToValue(endColor.rgb()));
×
523
            knob->blockSignals(false);
×
524
        }
525
        else if (control->m_type == VCMatrixControl::StartColor)
×
526
        {
527
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
528
            button->setDown(startColor == control->m_color);
×
529
        }
530
        else if (control->m_type == VCMatrixControl::EndColor)
×
531
        {
532
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
533
            button->setDown(endColor == control->m_color);
×
534
        }
535
        else if (control->m_type == VCMatrixControl::Animation)
×
536
        {
537
            bool on = false;
×
538
            if (algorithmType == RGBAlgorithm::Script)
×
539
            {
540
                if (algorithmName == control->m_resource)
×
541
                {
542
                    on = true;
×
543
                    for (QHash<QString, QString>::const_iterator it = control->m_properties.begin();
×
544
                            it != control->m_properties.end(); ++it)
×
545
                    {
546
                        if (algorithmProperties.value(it.key(), QString()) != it.value())
×
547
                            on = false;
×
548
                    }
549
                }
550
            }
551
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
552
            button->setDown(on);
×
553
        }
554
        else if (control->m_type == VCMatrixControl::Text)
×
555
        {
556
            bool on = false;
×
557
            if (algorithmType == RGBAlgorithm::Text)
×
558
            {
559
                if (algorithmText == control->m_resource)
×
560
                {
561
                    on = true;
×
562
                }
563
            }
564
            QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
565
            button->setDown(on);
×
566
        }
567
    }
568

569
    updateFeedback();
×
570
}
571

572
FunctionParent VCMatrix::functionParent() const
×
573
{
574
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
575
}
576

577
/*********************************************************************
578
 * Instant changes apply
579
 *********************************************************************/
580

581
void VCMatrix::setInstantChanges(bool instantly)
×
582
{
583
    m_instantApply = instantly;
×
584
}
×
585

586
bool VCMatrix::instantChanges() const
×
587
{
588
    return m_instantApply;
×
589
}
590

591
/*********************************************************************
592
 * Custom controls
593
 *********************************************************************/
594

595
void VCMatrix::addCustomControl(VCMatrixControl const& control)
×
596
{
597
    QWidget *controlWidget = NULL;
×
598

599
    if (control.m_type == VCMatrixControl::StartColor)
×
600
    {
601
        QPushButton *controlButton = new QPushButton(this);
×
602
        controlWidget = controlButton;
×
603
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
604
        controlButton->setFixedWidth(36);
×
605
        controlButton->setFocusPolicy(Qt::TabFocus);
×
606
        controlButton->setText("S");
×
607
    }
608
    else if (control.m_type == VCMatrixControl::EndColor)
×
609
    {
610
        QPushButton *controlButton = new QPushButton(this);
×
611
        controlWidget = controlButton;
×
612
        controlButton->setStyleSheet(controlBtnSS.arg(control.m_color.name()));
×
613
        controlButton->setFixedWidth(36);
×
614
        controlButton->setFocusPolicy(Qt::TabFocus);
×
615
        controlButton->setText("E");
×
616
    }
617
    else if (control.m_type == VCMatrixControl::ResetEndColor)
×
618
    {
619
        QPushButton *controlButton = new QPushButton(this);
×
620
        controlWidget = controlButton;
×
621
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
622
        controlButton->setMinimumWidth(36);
×
623
        controlButton->setMaximumWidth(80);
×
624
        controlButton->setFocusPolicy(Qt::TabFocus);
×
625
        QString btnLabel = tr("End Color Reset");
×
626
        controlButton->setToolTip(btnLabel);
×
627
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
628
    }
629
    else if (control.m_type == VCMatrixControl::Animation ||
×
630
             control.m_type == VCMatrixControl::Text)
×
631
    {
632
        QPushButton *controlButton = new QPushButton(this);
×
633
        controlWidget = controlButton;
×
634
        controlButton->setStyleSheet(controlBtnSS.arg("#BBBBBB"));
×
635
        controlButton->setMinimumWidth(36);
×
636
        controlButton->setMaximumWidth(80);
×
637
        controlButton->setFocusPolicy(Qt::TabFocus);
×
638
        QString btnLabel = control.m_resource;
×
639
        if (!control.m_properties.isEmpty())
×
640
        {
641
            btnLabel += " (";
×
642
            QHashIterator<QString, QString> it(control.m_properties);
×
643
            while(it.hasNext())
×
644
            {
645
                it.next();
×
646
                btnLabel += it.value();
×
647
                if (it.hasNext())
×
648
                    btnLabel += ",";
×
649
            }
650
            btnLabel += ")";
×
651
        }
652
        controlButton->setToolTip(btnLabel);
×
653
        controlButton->setText(fontMetrics().elidedText(btnLabel, Qt::ElideRight, 72));
×
654
    }
655
    else if (control.m_type == VCMatrixControl::StartColorKnob)
×
656
    {
657
        KnobWidget *controlKnob = new KnobWidget(this);
×
658
        controlWidget = controlKnob;
×
659
        controlKnob->setColor(control.m_color);
×
660
        controlKnob->setFixedWidth(36);
×
661
        controlKnob->setFixedHeight(36);
×
662
        QString knobLabel;
×
663
        if (control.m_color == Qt::red)
×
664
            knobLabel = tr("Start color Red component");
×
665
        else if (control.m_color == Qt::green)
×
666
            knobLabel = tr("Start color Green component");
×
667
        else if (control.m_color == Qt::blue)
×
668
            knobLabel = tr("Start color Blue component");
×
669
        controlKnob->setToolTip(knobLabel);
×
670
    }
671
    else if (control.m_type == VCMatrixControl::EndColorKnob)
×
672
    {
673
        KnobWidget *controlKnob = new KnobWidget(this);
×
674
        controlWidget = controlKnob;
×
675
        controlKnob->setColor(control.m_color.darker(250));
×
676
        controlKnob->setFixedWidth(36);
×
677
        controlKnob->setFixedHeight(36);
×
678
        QString knobLabel;
×
679
        if (control.m_color == Qt::red)
×
680
            knobLabel = tr("End color Red component");
×
681
        else if (control.m_color == Qt::green)
×
682
            knobLabel = tr("End color Green component");
×
683
        else if (control.m_color == Qt::blue)
×
684
            knobLabel = tr("End color Blue component");
×
685
        controlKnob->setToolTip(knobLabel);
×
686
    }
687

688
    Q_ASSERT(controlWidget != NULL);
×
689

690
    if (control.widgetType() == VCMatrixControl::Knob)
×
691
    {
692
        connect(reinterpret_cast<KnobWidget*>(controlWidget), SIGNAL(valueChanged(int)),
×
693
                this, SLOT(slotCustomControlValueChanged()));
694
    }
695
    else
696
    {
697
        connect(reinterpret_cast<QPushButton*>(controlWidget), SIGNAL(clicked()),
×
698
                this, SLOT(slotCustomControlClicked()));
699
    }
700

701

702
    if (mode() == Doc::Design)
×
703
        controlWidget->setEnabled(false);
×
704

705
    m_controls[controlWidget] = new VCMatrixControl(control);
×
706
    m_controlsLayout->addWidget(controlWidget);
×
707

708
    if (m_controls[controlWidget]->m_inputSource != NULL)
×
709
    {
710
        setInputSource(m_controls[controlWidget]->m_inputSource, m_controls[controlWidget]->m_id);
×
711
    }
712

713
    slotFunctionChanged(); // Start update timer
×
714
}
×
715

716
void VCMatrix::resetCustomControls()
×
717
{
718
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
719
            it != m_controls.end(); ++it)
×
720
    {
721
        QWidget* widget = it.key();
×
722
        m_controlsLayout->removeWidget(widget);
×
723
        delete widget;
×
724

725
        VCMatrixControl* control = it.value();
×
726
        if (!control->m_inputSource.isNull())
×
727
            setInputSource(QSharedPointer<QLCInputSource>(), control->m_id);
×
728
        delete control;
×
729
    }
730
    m_controls.clear();
×
731
}
×
732

733
QList<VCMatrixControl *> VCMatrix::customControls() const
×
734
{
735
    QList<VCMatrixControl*> controls = m_controls.values();
×
736
    std::sort(controls.begin(), controls.end(), VCMatrixControl::compare);
×
737
    return controls;
×
738
}
739

740
void VCMatrix::slotCustomControlClicked()
×
741
{
742
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
×
743
    VCMatrixControl *control = m_controls[btn];
×
744
    if (control != NULL)
×
745
    {
746
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
747
        if (matrix == NULL || mode() == Doc::Design)
×
748
            return;
×
749

750
        if (control->m_type == VCMatrixControl::StartColor)
×
751
        {
752
            matrix->setStartColor(control->m_color);
×
753
            if (instantChanges() == true)
×
754
                matrix->updateColorDelta();
×
755
            btn->setDown(true);
×
756
        }
757
        else if (control->m_type == VCMatrixControl::EndColor)
×
758
        {
759
            matrix->setEndColor(control->m_color);
×
760
            if (instantChanges() == true)
×
761
                matrix->updateColorDelta();
×
762
            btn->setDown(true);
×
763
        }
764
        else if (control->m_type == VCMatrixControl::ResetEndColor)
×
765
        {
766
            matrix->setEndColor(QColor());
×
767
            if (instantChanges() == true)
×
768
                matrix->updateColorDelta();
×
769
        }
770
        else if (control->m_type == VCMatrixControl::Animation)
×
771
        {
772
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, control->m_resource);
×
773
            if (!control->m_properties.isEmpty())
×
774
            {
775
                RGBScript *script = static_cast<RGBScript*> (algo);
×
776
                QHashIterator<QString, QString> it(control->m_properties);
×
777
                while(it.hasNext())
×
778
                {
779
                    it.next();
×
780
                    script->setProperty(it.key(), it.value());
×
781
                    matrix->setProperty(it.key(), it.value());
×
782
                }
783
            }
784
            matrix->setAlgorithm(algo);
×
785
            if (instantChanges() == true)
×
786
                matrix->updateColorDelta();
×
787
            btn->setDown(true);
×
788
        }
789
        else if (control->m_type == VCMatrixControl::Text)
×
790
        {
791
            RGBAlgorithm* algo = RGBAlgorithm::algorithm(m_doc, "Text");
×
792
            RGBText* text = static_cast<RGBText*> (algo);
×
793
            text->setText(control->m_resource);
×
794
            matrix->setAlgorithm(algo);
×
795
            if (instantChanges() == true)
×
796
                matrix->updateColorDelta();
×
797
            btn->setDown(true);
×
798
        }
799
    }
800
}
801

802
void VCMatrix::slotCustomControlValueChanged()
×
803
{
804
    KnobWidget *knob = qobject_cast<KnobWidget*>(sender());
×
805
    VCMatrixControl *control = m_controls[knob];
×
806
    if (control != NULL)
×
807
    {
808
        RGBMatrix* matrix = qobject_cast<RGBMatrix*>(m_doc->function(m_matrixID));
×
809
        if (matrix == NULL || mode() == Doc::Design)
×
810
            return;
×
811

812
        if (control->m_type == VCMatrixControl::StartColorKnob)
×
813
        {
814
            QRgb color = matrix->startColor().rgb();
×
815
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
816
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
817

818
            matrix->setStartColor(color);
×
819
            if (instantChanges() == true)
×
820
                matrix->updateColorDelta();
×
821
        }
822
        else if (control->m_type == VCMatrixControl::EndColorKnob)
×
823
        {
824
            QRgb color = matrix->endColor().rgb();
×
825
            QRgb knobValueColor = control->valueToRgb(knob->value());
×
826
            color = (color & ~control->m_color.rgb()) | (knobValueColor & control->m_color.rgb());
×
827

828
            matrix->setEndColor(color);
×
829
            if (instantChanges() == true)
×
830
                matrix->updateColorDelta();
×
831
        }
832
        else
833
        {
834
            // We are not supposed to be here
835
            Q_ASSERT(false);
×
836
        }
837
    }
838
}
839

840
void VCMatrix::slotModeChanged(Doc::Mode mode)
×
841
{
842
    if (mode == Doc::Operate)
×
843
        enableWidgetUI(true);
×
844
    else
845
        enableWidgetUI(false);
×
846

847
    VCWidget::slotModeChanged(mode);
×
848
}
×
849

850
/*********************************************************************
851
 * External input
852
 *********************************************************************/
853

854
void VCMatrix::slotKeyPressed(const QKeySequence &keySequence)
×
855
{
856
    if (acceptsInput() == false)
×
857
        return;
×
858

859
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
860
            it != m_controls.end(); ++it)
×
861
    {
862
        VCMatrixControl *control = it.value();
×
863
        if (control->m_keySequence == keySequence &&
×
864
                control->widgetType() == VCMatrixControl::Button) // Only for buttons
×
865
        {
866
            QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
867
            button->click();
×
868
        }
869
    }
870
}
871

872
void VCMatrix::updateFeedback()
×
873
{
874
    sendFeedback(m_slider->value());
×
875

876
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
877
            it != m_controls.end(); ++it)
×
878
    {
879
        VCMatrixControl *control = it.value();
×
880
        if (control->m_inputSource != NULL)
×
881
        {
882
            if (control->widgetType() == VCMatrixControl::Knob)
×
883
            {
884
                KnobWidget* knob = reinterpret_cast<KnobWidget*>(it.key());
×
885
                sendFeedback(knob->value(), control->m_inputSource);
×
886
            }
887
            else // if (control->widgetType() == VCMatrixControl::Button)
888
            {
889
                QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
×
890
                sendFeedback(button->isDown() ?
×
891
                                 control->m_inputSource->upperValue() :
×
892
                                 control->m_inputSource->lowerValue(),
×
893
                                 control->m_inputSource);
×
894
            }
895
        }
896
    }
897
}
×
898

899
void VCMatrix::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
900
{
901
    /* Don't let input data through in design mode or if disabled */
902
    if (acceptsInput() == false)
×
903
        return;
×
904

905
    quint32 pagedCh = (page() << 16) | channel;
×
906

907
    if (checkInputSource(universe, pagedCh, value, sender()))
×
908
    {
909
        m_slider->setValue((int) value);
×
910
        return;
×
911
    }
912

913
    for (QHash<QWidget *, VCMatrixControl *>::iterator it = m_controls.begin();
×
914
            it != m_controls.end(); ++it)
×
915
    {
916
        VCMatrixControl *control = it.value();
×
917
        if (control->m_inputSource != NULL &&
×
918
                control->m_inputSource->universe() == universe &&
×
919
                control->m_inputSource->channel() == pagedCh)
×
920
        {
921
            if (control->widgetType() == VCMatrixControl::Knob)
×
922
            {
923
                KnobWidget* knob = reinterpret_cast<KnobWidget*>(it.key());
×
924
                knob->setValue(value);
×
925
            }
926
            else
927
            {
928
                QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
929
                button->click();
×
930
            }
931
        }
932
    }
933
}
934

935
bool VCMatrix::loadXML(QXmlStreamReader &root)
×
936
{
937
    QString str;
×
938

939
    if (root.name() != KXMLQLCVCMatrix)
×
940
    {
941
        qWarning() << Q_FUNC_INFO << "Matrix node not found";
×
942
        return false;
×
943
    }
944

945
    /* Widget commons */
946
    loadXMLCommon(root);
×
947

948
    // Sorted list for new controls
949
    QList<VCMatrixControl> newControls;
×
950

951
    /* Children */
952
    while (root.readNextStartElement())
×
953
    {
954
        if (root.name() == KXMLQLCWindowState)
×
955
        {
956
            bool visible = false;
×
957
            int x = 0, y = 0, w = 0, h = 0;
×
958
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
×
959
            setGeometry(x, y, w, h);
×
960
        }
961
        else if (root.name() == KXMLQLCVCWidgetAppearance)
×
962
        {
963
            loadXMLAppearance(root);
×
964
        }
965
        else if (root.name() == KXMLQLCVCMatrixFunction)
×
966
        {
967
            QXmlStreamAttributes attrs = root.attributes();
×
968
            str = attrs.value(KXMLQLCVCMatrixFunctionID).toString();
×
969
            setFunction(str.toUInt());
×
970
            if (attrs.hasAttribute(KXMLQLCVCMatrixInstantApply))
×
971
                setInstantChanges(true);
×
972
            root.skipCurrentElement();
×
973
        }
974
        else if (root.name() == KXMLQLCVCWidgetInput)
×
975
        {
976
            loadXMLInput(root);
×
977
        }
978
        else if(root.name() == KXMLQLCVCMatrixControl)
×
979
        {
980
            VCMatrixControl control(0xff);
×
981
            if (control.loadXML(root))
×
982
                newControls.insert(std::lower_bound(newControls.begin(), newControls.end(), control), control);
×
983
        }
984
        else if (root.name() == KXMLQLCVCMatrixVisibilityMask)
×
985
        {
986
            setVisibilityMask(root.readElementText().toUInt());
×
987
        }
988
        else
989
        {
990
            qWarning() << Q_FUNC_INFO << "Unknown VCMatrix tag:" << root.name().toString();
×
991
            root.skipCurrentElement();
×
992
        }
993
    }
994

995
    foreach (VCMatrixControl const& control, newControls)
×
996
        addCustomControl(control);
×
997

998
    return true;
×
999
}
1000

1001
bool VCMatrix::saveXML(QXmlStreamWriter *doc)
×
1002
{
1003
    Q_ASSERT(doc != NULL);
×
1004

1005
    /* VC button entry */
1006
    doc->writeStartElement(KXMLQLCVCMatrix);
×
1007

1008
    saveXMLCommon(doc);
×
1009

1010
    /* Window state */
1011
    saveXMLWindowState(doc);
×
1012

1013
    /* Appearance */
1014
    saveXMLAppearance(doc);
×
1015

1016
    /* Function */
1017
    doc->writeStartElement(KXMLQLCVCMatrixFunction);
×
1018
    doc->writeAttribute(KXMLQLCVCMatrixFunctionID, QString::number(function()));
×
1019

1020
    if (instantChanges() == true)
×
1021
        doc->writeAttribute(KXMLQLCVCMatrixInstantApply, "true");
×
1022
    doc->writeEndElement();
×
1023

1024
    /* Default controls visibility  */
1025
    if (m_visibilityMask != VCMatrix::defaultVisibilityMask())
×
1026
        doc->writeTextElement(KXMLQLCVCMatrixVisibilityMask, QString::number(m_visibilityMask));
×
1027

1028
    /* Slider External input */
1029
    saveXMLInput(doc);
×
1030

1031
    foreach(VCMatrixControl *control, customControls())
×
1032
        control->saveXML(doc);
×
1033

1034
    /* End the <Matrix> tag */
1035
    doc->writeEndElement();
×
1036

1037
    return true;
×
1038
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc