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

mcallegari / qlcplus / 9191387690

22 May 2024 12:35PM UTC coverage: 32.007% (-0.007%) from 32.014%
9191387690

Pull #1567

github

web-flow
Merge ba1929c17 into bfa4d2dd4
Pull Request #1567: Add merger mode for HIDDMXDevices (DE/FX5/Nodle)

15399 of 48111 relevant lines covered (32.01%)

22970.98 hits per line

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

37.16
/ui/src/virtualconsole/vcxypad.cpp
1
/*
2
  Q Light Controller Plus
3
  vcxypad.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Stefan Krumm
7
                Massimo Callegari
8

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

13
      http://www.apache.org/licenses/LICENSE-2.0.txt
14

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

22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QTreeWidgetItem>
25
#include <QTreeWidget>
26
#include <QMouseEvent>
27
#include <QMessageBox>
28
#include <QGridLayout>
29
#include <QByteArray>
30
#include <QSettings>
31
#include <QPainter>
32
#include <QPixmap>
33
#include <QCursor>
34
#include <QSlider>
35
#include <qmath.h>
36
#include <QDebug>
37
#include <QPoint>
38
#include <QMenu>
39
#include <QList>
40

41
#include "qlcmacros.h"
42

43
#include "vcpropertieseditor.h"
44
#include "vcxypadproperties.h"
45
#include "ctkrangeslider.h"
46
#include "mastertimer.h"
47
#include "vcxypadarea.h"
48
#include "flowlayout.h"
49
#include "vcxypad.h"
50
#include "fixture.h"
51
#include "apputil.h"
52
#include "scene.h"
53
#include "efx.h"
54
#include "doc.h"
55

56
const quint8 VCXYPad::panInputSourceId = 0;
57
const quint8 VCXYPad::tiltInputSourceId = 1;
58
const quint8 VCXYPad::widthInputSourceId = 2;
59
const quint8 VCXYPad::heightInputSourceId = 3;
60

61
const qreal MAX_VALUE = 256.0;
62
const qreal MAX_DMX_VALUE = MAX_VALUE - 1.0/256;
63

64
static const QString presetBtnSS = "QPushButton { background-color: %1; height: 32px; border: 2px solid #6A6A6A; border-radius: 5px; }"
65
                                   "QPushButton:pressed { border: 2px solid #0000FF; }"
66
                                   "QPushButton:checked { border: 2px solid #0000FF; }"
67
                                   "QPushButton:unchecked { border: 2px solid #6A6A6A; }"
68
                                   "QPushButton:disabled { border: 2px solid #BBBBBB; color: #8f8f8f }";
69

70
/*****************************************************************************
71
 * VCXYPad Initialization
72
 *****************************************************************************/
73

74
VCXYPad::VCXYPad(QWidget* parent, Doc* doc) : VCWidget(parent, doc)
9✔
75
{
76
    /* Set the class name "VCXYPad" as the object name as well */
77
    setObjectName(VCXYPad::staticMetaObject.className());
9✔
78

79
    m_mainVbox = new QVBoxLayout(this);
9✔
80

81
    m_padBox = new QHBoxLayout;
9✔
82
    m_mainVbox->addLayout(m_padBox);
9✔
83

84
    m_lvbox = new QVBoxLayout;
9✔
85
    m_lvbox->addSpacing(20);
9✔
86
    // left side vertical range slider
87
    m_vRangeSlider = new ctkRangeSlider(this);
9✔
88
    m_lvbox->addWidget(m_vRangeSlider);
9✔
89
    m_lvbox->addSpacing(25);
9✔
90

91
    m_padBox->addLayout(m_lvbox);
9✔
92

93
    m_cvbox = new QVBoxLayout;
9✔
94
    m_padBox->addLayout(m_cvbox);
9✔
95

96
    // top horizontal range slider
97
    m_hRangeSlider = new ctkRangeSlider(Qt::Horizontal, this);
9✔
98
    m_cvbox->addWidget(m_hRangeSlider);
9✔
99

100
    // central XYPad
101
    m_area = new VCXYPadArea(this);
9✔
102
    m_cvbox->addWidget(m_area);
9✔
103

104
    // bottom horizontal slider
105
    m_hSlider = new QSlider(Qt::Horizontal, this);
9✔
106
    m_cvbox->addWidget(m_hSlider);
9✔
107

108
    m_rvbox = new QVBoxLayout;
9✔
109
    m_padBox->addLayout(m_rvbox);
9✔
110
    m_rvbox->addSpacing(20);
9✔
111

112
    // left side vertical slider
113
    m_vSlider = new QSlider(this);
9✔
114
    m_rvbox->addWidget(m_vSlider);
9✔
115
    m_rvbox->addSpacing(25);
9✔
116

117
    // bottom preset space
118
    m_presetsLayout = new FlowLayout();
9✔
119
    m_mainVbox->addLayout(m_presetsLayout);
9✔
120
    m_efx = NULL;
9✔
121
    m_efxStartXOverrideId = Function::invalidAttributeId();
9✔
122
    m_efxStartYOverrideId = Function::invalidAttributeId();
9✔
123
    m_efxWidthOverrideId = Function::invalidAttributeId();
9✔
124
    m_efxHeightOverrideId = Function::invalidAttributeId();
9✔
125

126
    m_scene = NULL;
9✔
127

128
    m_vSlider->setRange(0, 256);
9✔
129
    m_hSlider->setRange(0, 256);
9✔
130
    m_vSlider->setInvertedAppearance(true);
9✔
131
    m_vSlider->setTickPosition(QSlider::TicksLeft);
9✔
132
    m_vSlider->setTickInterval(16);
9✔
133
    m_hSlider->setTickPosition(QSlider::TicksAbove);
9✔
134
    m_hSlider->setTickInterval(16);
9✔
135
    m_vSlider->setStyle(AppUtil::saneStyle());
9✔
136
    m_hSlider->setStyle(AppUtil::saneStyle());
9✔
137

138
    m_hRangeSlider->setRange(0, 256);
9✔
139
    m_vRangeSlider->setInvertedAppearance(true);
9✔
140
    m_vRangeSlider->setRange(0, 256);
9✔
141
    m_hRangeSlider->setMaximumPosition(256);
9✔
142
    m_vRangeSlider->setMaximumPosition(256);
9✔
143

144
    connect(m_area, SIGNAL(positionChanged(const QPointF&)),
9✔
145
            this, SLOT(slotPositionChanged(const QPointF&)));
146
    connect(this, SIGNAL(fixturePositions(const QVariantList)),
18✔
147
            m_area, SLOT(slotFixturePositions(const QVariantList)));
9✔
148
    connect(m_vSlider, SIGNAL(valueChanged(int)),
9✔
149
            this, SLOT(slotSliderValueChanged()));
150
    connect(m_hSlider, SIGNAL(valueChanged(int)),
9✔
151
            this, SLOT(slotSliderValueChanged()));
152
    connect(m_hRangeSlider, SIGNAL(positionsChanged(int,int)),
9✔
153
            this, SLOT(slotRangeValueChanged()));
154
    connect(m_vRangeSlider, SIGNAL(positionsChanged(int,int)),
9✔
155
            this, SLOT(slotRangeValueChanged()));
156

157
    setFrameStyle(KVCFrameStyleSunken);
9✔
158
    setType(VCWidget::XYPadWidget);
9✔
159
    setCaption("XY Pad");
9✔
160
    setMinimumSize(20, 20);
9✔
161

162
    QSettings settings;
18✔
163
    QVariant var = settings.value(SETTINGS_XYPAD_SIZE);
18✔
164
    if (var.isValid() == true)
9✔
165
        resize(var.toSize());
×
166
    else
167
        resize(QSize(230, 230));
9✔
168
    m_padInteraction = false;
9✔
169
    m_sliderInteraction = false;
9✔
170
    m_inputValueChanged = false;
9✔
171

172
    slotModeChanged(m_doc->mode());
9✔
173
    setLiveEdit(m_liveEdit);
9✔
174

175
    m_doc->masterTimer()->registerDMXSource(this);
9✔
176
    connect(m_doc->inputOutputMap(), SIGNAL(universeWritten(quint32,QByteArray)),
9✔
177
            this, SLOT(slotUniverseWritten(quint32,QByteArray)));
178
}
9✔
179

180
VCXYPad::~VCXYPad()
12✔
181
{
182
    m_doc->masterTimer()->unregisterDMXSource(this);
9✔
183
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
18✔
184
    {
185
        if (!fader.isNull())
×
186
            fader->requestDelete();
×
187
    }
188
    m_fadersMap.clear();
9✔
189
}
12✔
190

191
void VCXYPad::enableWidgetUI(bool enable)
11✔
192
{
193
    m_vSlider->setEnabled(enable);
11✔
194
    m_hSlider->setEnabled(enable);
11✔
195
    m_area->setMode(enable ? Doc::Operate : Doc::Design);
11✔
196

197
    QMutableListIterator <VCXYPadFixture> it(m_fixtures);
11✔
198
    while (it.hasNext() == true)
13✔
199
    {
200
        VCXYPadFixture fxi = it.next();
4✔
201
        if (enable)
2✔
202
            fxi.arm();
1✔
203
        else
204
            fxi.disarm();
1✔
205
        it.setValue(fxi);
2✔
206
    }
207

208
    foreach (QWidget *presetBtn, m_presets.keys())
22✔
209
        presetBtn->setEnabled(enable);
×
210

211
    /* Reset the changed flag in m_area so that the pad won't immediately set a value
212
       when mode is changed */
213
    m_area->position();
11✔
214
}
11✔
215

216
/*****************************************************************************
217
 * Clipboard
218
 *****************************************************************************/
219

220
VCWidget* VCXYPad::createCopy(VCWidget* parent)
1✔
221
{
222
    Q_ASSERT(parent != NULL);
1✔
223

224
    VCXYPad* xypad = new VCXYPad(parent, m_doc);
1✔
225
    if (xypad->copyFrom(this) == false)
1✔
226
    {
227
        delete xypad;
×
228
        xypad = NULL;
×
229
    }
230

231
    for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
1✔
232
            it != m_presets.end(); ++it)
1✔
233
    {
234
        VCXYPadPreset *preset = it.value();
×
235
        xypad->addPreset(*preset);
×
236
    }
237

238
    return xypad;
1✔
239
}
240

241
bool VCXYPad::copyFrom(const VCWidget* widget)
1✔
242
{
243
    const VCXYPad* xypad = qobject_cast <const VCXYPad*> (widget);
1✔
244
    if (xypad == NULL)
1✔
245
        return false;
×
246
    resize(xypad->size());
1✔
247

248
    /* Get rid of existing channels */
249
    m_fixtures.clear();
1✔
250

251
    /* Copy the other widget's fixtures */
252
    m_fixtures = xypad->fixtures();
1✔
253

254
    /* Copy the current position */
255
    m_area->setPosition(xypad->m_area->position());
1✔
256
    m_vSlider->setValue(xypad->m_vSlider->value());
1✔
257
    m_hSlider->setValue(xypad->m_hSlider->value());
1✔
258

259
    /* Copy common stuff */
260
    return VCWidget::copyFrom(widget);
1✔
261
}
262

263
/*****************************************************************************
264
 * Caption
265
 *****************************************************************************/
266

267
void VCXYPad::setCaption(const QString& text)
12✔
268
{
269
    m_area->setWindowTitle(text);
12✔
270
    VCWidget::setCaption(text);
12✔
271
}
12✔
272

273
bool VCXYPad::invertedAppearance() const
7✔
274
{
275
    return !(m_vSlider->invertedAppearance());
7✔
276
}
277

278
void VCXYPad::setInvertedAppearance(bool invert)
×
279
{
280
    if (invert == true)
×
281
        m_vSlider->setInvertedAppearance(false);
×
282
    else
283
        m_vSlider->setInvertedAppearance(true);
×
284
}
×
285

286
/*****************************************************************************
287
 * Properties
288
 *****************************************************************************/
289

290
void VCXYPad::editProperties()
×
291
{
292
    VCXYPadProperties prop(this, m_doc);
×
293
    if (prop.exec() == QDialog::Accepted)
×
294
        m_doc->setModified();
×
295
}
×
296

297
/*****************************************************************************
298
 * Fixtures
299
 *****************************************************************************/
300

301
void VCXYPad::appendFixture(const VCXYPadFixture& fxi)
17✔
302
{
303
    if (fxi.head().isValid() && m_fixtures.indexOf(fxi) == -1)
17✔
304
        m_fixtures.append(fxi);
13✔
305

306
    updateDegreesRange();
17✔
307
}
17✔
308

309
void VCXYPad::removeFixture(GroupHead const & head)
2✔
310
{
311
    VCXYPadFixture fixture(m_doc);
4✔
312
    fixture.setHead(head);
2✔
313

314
    m_fixtures.removeAll(fixture);
2✔
315

316
    updateDegreesRange();
2✔
317
}
2✔
318

319
void VCXYPad::clearFixtures()
1✔
320
{
321
    m_fixtures.clear();
1✔
322

323
    updateDegreesRange();
1✔
324
}
1✔
325

326
QList <VCXYPadFixture> VCXYPad::fixtures() const
8✔
327
{
328
    return m_fixtures;
8✔
329
}
330

331
QRectF VCXYPad::computeCommonDegreesRange() const
20✔
332
{
333
    QRectF commonRange;
20✔
334

335
    foreach (VCXYPadFixture fixture, m_fixtures)
22✔
336
    {
337
        QRectF range = fixture.degreesRange();
18✔
338
        if (!range.isValid())
18✔
339
            return QRectF();
17✔
340

341
        if (commonRange.isValid())
1✔
342
        {
343
            if (range != commonRange)
×
344
                return QRectF();
×
345
        }
346
        else
347
        {
348
            commonRange = range;
1✔
349
        }
350
    }
351

352
    return commonRange;
3✔
353
}
354

355
void VCXYPad::updateDegreesRange()
20✔
356
{
357
    QRectF range = computeCommonDegreesRange();
20✔
358

359
    m_area->setDegreesRange(range);
20✔
360
}
20✔
361

362
/*****************************************************************************
363
 * Current XY position
364
 *****************************************************************************/
365

366
void VCXYPad::writeDMX(MasterTimer* timer, QList<Universe *> universes)
×
367
{
368
    if (m_scene != NULL)
×
369
        writeScenePositions(timer, universes);
×
370
    else
371
        writeXYFixtures(timer, universes);
×
372
}
×
373

374
void VCXYPad::writeXYFixtures(MasterTimer *timer, QList<Universe *> universes)
×
375
{
376
    Q_UNUSED(timer);
377

378
    if (m_area->hasPositionChanged() == false)
×
379
        return;
×
380

381
    // This call also resets the m_changed flag in m_area
382
    QPointF pt = m_area->position();
×
383

384
    /* Scale XY coordinate values to 0.0 - 1.0 */
385
    qreal x = SCALE(pt.x(), qreal(0), qreal(256), qreal(0), qreal(1));
×
386
    qreal y = SCALE(pt.y(), qreal(0), qreal(256), qreal(0), qreal(1));
×
387

388
    if (invertedAppearance())
×
389
        y = qreal(1) - y;
×
390

391
    /* Write values outside of mutex lock to keep UI snappy */
392
    foreach (VCXYPadFixture fixture, m_fixtures)
×
393
    {
394
        if (fixture.isEnabled())
×
395
        {
396
            quint32 universe = fixture.universe();
×
397
            if (universe == Universe::invalid())
×
398
                continue;
×
399

400
            QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
×
401
            if (fader.isNull())
×
402
            {
403
                fader = universes[universe]->requestFader();
×
404
                fader->adjustIntensity(intensity());
×
405
                m_fadersMap[universe] = fader;
×
406
            }
407
            fixture.writeDMX(x, y, fader, universes[universe]);
×
408
        }
409
    }
410
}
411

412
void VCXYPad::updateSceneChannel(FadeChannel *fc, uchar value)
×
413
{
414
    fc->addFlag(FadeChannel::Relative);
×
415
    fc->setStart(value);
×
416
    fc->setCurrent(value);
×
417
    fc->setTarget(value);
×
418
    fc->setElapsed(0);
×
419
    fc->setReady(false);
×
420
}
×
421

422
void VCXYPad::writeScenePositions(MasterTimer *timer, QList<Universe *> universes)
×
423
{
424
    Q_UNUSED(timer);
425

426
    if (m_scene == NULL || m_scene->isRunning() == false)
×
427
        return;
×
428

429
    QPointF pt = m_area->position();
×
430
    uchar panCoarse = uchar(qFloor(pt.x()));
×
431
    uchar panFine = uchar((pt.x() - qFloor(pt.x())) * 256);
×
432
    uchar tiltCoarse = uchar(qFloor(pt.y()));
×
433
    uchar tiltFine = uchar((pt.y() - qFloor(pt.y())) * 256);
×
434

435
    foreach (SceneChannel sc, m_sceneChannels)
×
436
    {
437
        if (sc.m_universe >= (quint32)universes.count())
×
438
            continue;
×
439

440
        QSharedPointer<GenericFader> fader = m_fadersMap.value(sc.m_universe, QSharedPointer<GenericFader>());
×
441
        if (fader.isNull())
×
442
        {
443
            fader = universes[sc.m_universe]->requestFader();
×
444
            fader->adjustIntensity(intensity());
×
445
            m_fadersMap[sc.m_universe] = fader;
×
446
        }
447

448
        if (sc.m_group == QLCChannel::Pan)
×
449
        {
450
            if (sc.m_subType == QLCChannel::MSB)
×
451
            {
452
                FadeChannel *fc = fader->getChannelFader(m_doc, universes[sc.m_universe], sc.m_fixture, sc.m_channel);
×
453
                updateSceneChannel(fc, panCoarse);
×
454
            }
455
            else
456
            {
457
                FadeChannel *fc = fader->getChannelFader(m_doc, universes[sc.m_universe], sc.m_fixture, sc.m_channel);
×
458
                updateSceneChannel(fc, panFine);
×
459
            }
460
        }
461
        else
462
        {
463
            if (sc.m_subType == QLCChannel::MSB)
×
464
            {
465
                FadeChannel *fc = fader->getChannelFader(m_doc, universes[sc.m_universe], sc.m_fixture, sc.m_channel);
×
466
                updateSceneChannel(fc, tiltCoarse);
×
467
            }
468
            else
469
            {
470
                FadeChannel *fc = fader->getChannelFader(m_doc, universes[sc.m_universe], sc.m_fixture, sc.m_channel);
×
471
                updateSceneChannel(fc, tiltFine);
×
472
            }
473
        }
474
    }
475
}
476

477
void VCXYPad::slotPositionChanged(const QPointF& pt)
6✔
478
{
479
    if (m_sliderInteraction == true)
6✔
480
        return;
×
481

482
    m_padInteraction = true;
6✔
483
    m_hSlider->setValue(pt.x());
6✔
484
    if (invertedAppearance() == false)
6✔
485
    {
486
        m_vSlider->setValue(pt.y());
6✔
487
    }
488
    else
489
    {
490
        m_vSlider->setValue(MAX_DMX_VALUE - pt.y());
×
491
    }
492

493
    if (m_inputValueChanged == false)
6✔
494
        updateFeedback();
6✔
495
    m_padInteraction = false;
6✔
496
    m_inputValueChanged = false;
6✔
497
}
498

499
void VCXYPad::slotSliderValueChanged()
10✔
500
{
501
    if (m_padInteraction == true)
10✔
502
        return;
10✔
503

504
    QPointF pt = m_area->position(false);
×
505

506
    m_sliderInteraction = true;
×
507
    if (QObject::sender() == m_hSlider)
×
508
    {
509
        pt.setX(m_hSlider->value());
×
510

511
        int Xfb = (int)SCALE(float(m_hSlider->value()), float(m_hSlider->minimum()),
×
512
                             float(m_hSlider->maximum()), float(0), float(UCHAR_MAX));
513
        sendFeedback(Xfb, panInputSourceId);
×
514
    }
515
    else
516
    {
517
        if (invertedAppearance() == false)
×
518
            pt.setY(m_vSlider->value());
×
519
        else
520
            pt.setY(MAX_DMX_VALUE - m_vSlider->value());
×
521

522
        int Yfb = (int)SCALE(float(m_vSlider->value()), float(m_vSlider->minimum()),
×
523
                             float(m_vSlider->maximum()), float(0), float(UCHAR_MAX));
524
        sendFeedback(Yfb, tiltInputSourceId);
×
525
    }
526

527
    m_area->setPosition(pt);
×
528
    m_area->update();
×
529
    m_sliderInteraction = false;
×
530
}
531

532
void VCXYPad::slotRangeValueChanged()
×
533
{
534
    QRectF rect(QPointF(m_hRangeSlider->minimumPosition(), m_vRangeSlider->minimumPosition()),
×
535
               QPointF(m_hRangeSlider->maximumPosition(), m_vRangeSlider->maximumPosition()));
×
536
    m_area->setRangeWindow(rect);
×
537
    if (m_efx != NULL && m_efx->isRunning())
×
538
    {
539
        m_efx->adjustAttribute(rect.x() + rect.width() / 2, m_efxStartXOverrideId);
×
540
        m_efx->adjustAttribute(rect.y() + rect.height() / 2, m_efxStartYOverrideId);
×
541
        m_efx->adjustAttribute(rect.width() / 2, m_efxWidthOverrideId);
×
542
        m_efx->adjustAttribute(rect.height() / 2, m_efxHeightOverrideId);
×
543

544
        // recalculate preview polygons
545
        QPolygonF polygon;
×
546
        m_efx->preview(polygon);
×
547

548
        QVector <QPolygonF> fixturePoints;
×
549
        m_efx->previewFixtures(fixturePoints);
×
550

551
        m_area->setEFXPolygons(polygon, fixturePoints);
×
552
        m_area->setEFXInterval(m_efx->duration());
×
553
    }
554
    m_area->update();
×
555
    if (QObject::sender() == m_hRangeSlider)
×
556
        sendFeedback(m_hRangeSlider->maximumValue(), heightInputSourceId);
×
557
    else if (QObject::sender() == m_vRangeSlider)
×
558
        sendFeedback(m_vRangeSlider->maximumValue(), widthInputSourceId);
×
559
}
×
560

561
void VCXYPad::slotUniverseWritten(quint32 idx, const QByteArray &universeData)
×
562
{
563
    QVariantList positions;
×
564

565
    if (m_scene)
×
566
    {
567
        QMap <quint32, QPointF> fxMap;
×
568

569
        foreach (SceneChannel sc, m_sceneChannels)
×
570
        {
571
            if (sc.m_universe != idx)
×
572
                continue;
×
573

574
            qreal x = fxMap[sc.m_fixture].x();
×
575
            qreal y = fxMap[sc.m_fixture].y();
×
576

577
            if (sc.m_group == QLCChannel::Pan)
×
578
            {
579
                if (sc.m_subType == QLCChannel::MSB)
×
580
                    x += (uchar)universeData.at(sc.m_channel);
×
581
                else
582
                    x += ((uchar)universeData.at(sc.m_channel) / 255);
×
583
            }
584
            else
585
            {
586
                if (sc.m_subType == QLCChannel::MSB)
×
587
                    y += (uchar)universeData.at(sc.m_channel);
×
588
                else
589
                    y += ((uchar)universeData.at(sc.m_channel) / 255);
×
590
            }
591
            fxMap[sc.m_fixture] = QPointF(x, y);
×
592
        }
593

594
        foreach (QPointF pt, fxMap.values())
×
595
        {
596
            if (invertedAppearance())
×
597
                pt.setY(256 - pt.y());
×
598
            positions.append(pt);
×
599
        }
600
    }
601
    else
602
    {
603
        foreach (VCXYPadFixture fixture, m_fixtures)
×
604
        {
605
            if (fixture.isEnabled() == false)
×
606
                continue;
×
607

608
            if (fixture.universe() != idx)
×
609
                continue;
×
610

611
            qreal x(-1), y(-1);
×
612
            fixture.readDMX(universeData, x, y);
×
613
            if (x != -1.0 && y != -1.0)
×
614
            {
615
                if (invertedAppearance())
×
616
                    y = qreal(1) - y;
×
617

618
               x *= 256;
×
619
               y *= 256;
×
620
               positions.append(QPointF(x, y));
×
621
            }
622
        }
623
    }
624

625
    emit fixturePositions(positions);
×
626
}
×
627

628
/*********************************************************************
629
 * Presets
630
 *********************************************************************/
631

632
void VCXYPad::addPreset(const VCXYPadPreset &preset)
×
633
{
634
    QString label = preset.m_name;
×
635

636
    if (label.isEmpty())
×
637
    {
638
        qDebug() << "VCXYPad Preset label empty. Not adding it";
×
639
        return;
×
640
    }
641

642
    QPushButton *presetButton = new QPushButton(this);
×
643
    QWidget *presetWidget = presetButton;
×
644
    presetButton->setStyleSheet(presetBtnSS.arg(preset.getColor()));
×
645
    presetButton->setMinimumWidth(36);
×
646
    presetButton->setMaximumWidth(80);
×
647
    presetButton->setFocusPolicy(Qt::TabFocus);
×
648
    presetButton->setText(fontMetrics().elidedText(label, Qt::ElideRight, 72));
×
649
    if (preset.m_type == VCXYPadPreset::EFX ||
×
650
        preset.m_type == VCXYPadPreset::Scene ||
×
651
        preset.m_type == VCXYPadPreset::FixtureGroup)
×
652
            presetButton->setCheckable(true);
×
653

654
    connect(presetButton, SIGNAL(clicked(bool)),
×
655
            this, SLOT(slotPresetClicked(bool)));
656

657
    if (mode() == Doc::Design)
×
658
        presetWidget->setEnabled(false);
×
659

660
    m_presets[presetWidget] = new VCXYPadPreset(preset);
×
661
    m_presetsLayout->addWidget(presetWidget);
×
662

663
    if (m_presets[presetWidget]->m_inputSource != NULL)
×
664
    {
665
        setInputSource(m_presets[presetWidget]->m_inputSource, m_presets[presetWidget]->m_id);
×
666
    }
667
}
668

669
void VCXYPad::resetPresets()
×
670
{
671
    for (QHash<QWidget *, VCXYPadPreset *>::iterator it = m_presets.begin();
×
672
            it != m_presets.end(); ++it)
×
673
    {
674
        QWidget* widget = it.key();
×
675
        m_presetsLayout->removeWidget(widget);
×
676
        delete widget;
×
677

678
        VCXYPadPreset* preset = it.value();
×
679
        if (!preset->m_inputSource.isNull())
×
680
            setInputSource(QSharedPointer<QLCInputSource>(), preset->m_id);
×
681
        delete preset;
×
682
    }
683
    m_presets.clear();
×
684
}
×
685

686
QList<VCXYPadPreset *> VCXYPad::presets() const
1✔
687
{
688
    QList<VCXYPadPreset*> presets = m_presets.values();
1✔
689
    std::sort(presets.begin(), presets.end(), VCXYPadPreset::compare);
1✔
690
    return presets;
1✔
691
}
692

693
QMap<quint32,QString> VCXYPad::presetsMap() const
×
694
{
695
    QMap<quint32,QString> map;
×
696

697
    foreach (VCXYPadPreset *control, m_presets.values())
×
698
        map.insert(control->m_id, VCXYPadPreset::typeToString(control->m_type));
×
699

700
    return map;
×
701
}
702

703
void VCXYPad::slotPresetClicked(bool checked)
×
704
{
705
    if (mode() == Doc::Design)
×
706
        return;
×
707

708
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
×
709
    VCXYPadPreset *preset = m_presets[btn];
×
710

711
    Q_ASSERT(preset != NULL);
×
712

713
    // stop any previously started EFX
714
    if (m_efx != NULL && m_efx->isRunning())
×
715
    {
716
        disconnect(m_efx, SIGNAL(durationChanged(uint)), this, SLOT(slotEFXDurationChanged(uint)));
×
717

718
        m_efx->stopAndWait();
×
719
        m_efx = NULL;
×
720
        m_efxStartXOverrideId = Function::invalidAttributeId();
×
721
        m_efxStartYOverrideId = Function::invalidAttributeId();
×
722
        m_efxWidthOverrideId = Function::invalidAttributeId();
×
723
        m_efxHeightOverrideId = Function::invalidAttributeId();
×
724
    }
725

726
    // stop any previously started Scene
727
    if (m_scene != NULL)
×
728
    {
729
        m_scene->stop(functionParent());
×
730
        m_scene = NULL;
×
731
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
732
        {
733
            if (!fader.isNull())
×
734
                fader->requestDelete();
×
735
        }
736
        m_fadersMap.clear();
×
737
    }
738

739
    // deactivate all previously activated buttons first
740
    for (QHash<QWidget *, VCXYPadPreset *>::iterator it = m_presets.begin();
×
741
            it != m_presets.end(); ++it)
×
742
    {
743
        QPushButton* cBtn = reinterpret_cast<QPushButton*>(it.key());
×
744
        VCXYPadPreset *cPr = it.value();
×
745
        if (preset->m_id == cPr->m_id)
×
746
            continue;
×
747

748
        cBtn->blockSignals(true);
×
749
        if (preset->m_type == VCXYPadPreset::FixtureGroup)
×
750
        {
751
            if (cPr->m_type == VCXYPadPreset::FixtureGroup &&
×
752
                cBtn->isChecked() == true)
×
753
            {
754
                cBtn->setChecked(false);
×
755
                if (cPr->m_inputSource.isNull() == false)
×
756
                    sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
757
            }
758
        }
759
        else if (cPr->m_type == VCXYPadPreset::EFX ||
×
760
            cPr->m_type == VCXYPadPreset::Scene)
×
761
        {
762
            if (cBtn->isChecked() == true)
×
763
            {
764
                cBtn->setChecked(false);
×
765
                if (cPr->m_inputSource.isNull() == false)
×
766
                    sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
767
            }
768
        }
769
        else
770
        {
771
            if (cBtn->isDown() == true)
×
772
            {
773
                cBtn->setDown(false);
×
774
                if (cPr->m_inputSource.isNull() == false)
×
775
                    sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
776
            }
777
        }
778
        cBtn->blockSignals(false);
×
779
        if (cPr->m_inputSource.isNull() == false)
×
780
            sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
781
    }
782

783
    if (preset->m_type == VCXYPadPreset::EFX)
×
784
    {
785
        if (checked == false)
×
786
        {
787
            m_area->enableEFXPreview(false);
×
788
            return;
×
789
        }
790

791
        Function *f = m_doc->function(preset->m_funcID);
×
792
        if (f == NULL || f->type() != Function::EFXType)
×
793
            return;
×
794
        m_efx = qobject_cast<EFX*>(f);
×
795

796
        QRectF rect(QPointF(m_hRangeSlider->minimumPosition(), m_vRangeSlider->minimumPosition()),
×
797
                   QPointF(m_hRangeSlider->maximumPosition(), m_vRangeSlider->maximumPosition()));
×
798
        m_area->setRangeWindow(rect);
×
799
        if (rect.isValid())
×
800
        {
801
            m_efxStartXOverrideId = m_efx->requestAttributeOverride(EFX::XOffset, rect.x() + rect.width() / 2);
×
802
            m_efxStartYOverrideId = m_efx->requestAttributeOverride(EFX::YOffset, rect.y() + rect.height() / 2);
×
803
            m_efxWidthOverrideId = m_efx->requestAttributeOverride(EFX::Width, rect.width() / 2);
×
804
            m_efxHeightOverrideId = m_efx->requestAttributeOverride(EFX::Height, rect.height() / 2);
×
805
        }
806

807
        QPolygonF polygon;
×
808
        m_efx->preview(polygon);
×
809

810
        QVector <QPolygonF> fixturePoints;
×
811
        m_efx->previewFixtures(fixturePoints);
×
812

813
        m_area->enableEFXPreview(true);
×
814
        m_area->setEFXPolygons(polygon, fixturePoints);
×
815
        m_area->setEFXInterval(m_efx->duration());
×
816
        m_efx->start(m_doc->masterTimer(), functionParent());
×
817

818
        connect(m_efx, SIGNAL(durationChanged(uint)), this, SLOT(slotEFXDurationChanged(uint)));
×
819

820
        if (preset->m_inputSource.isNull() == false)
×
821
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
822
    }
823
    else if (preset->m_type == VCXYPadPreset::Scene)
×
824
    {
825
        if (checked == false)
×
826
            return;
×
827

828
        Function *f = m_doc->function(preset->m_funcID);
×
829
        if (f == NULL || f->type() != Function::SceneType)
×
830
            return;
×
831

832
        m_scene = qobject_cast<Scene*>(f);
×
833
        m_sceneChannels.clear();
×
834

835
        foreach (SceneValue scv, m_scene->values())
×
836
        {
837
            Fixture *fixture = m_doc->fixture(scv.fxi);
×
838
            if (fixture == NULL)
×
839
                continue;
×
840
            const QLCChannel *ch = fixture->channel(scv.channel);
×
841
            if (ch == NULL)
×
842
                continue;
×
843
            if (ch->group() != QLCChannel::Pan && ch->group() != QLCChannel::Tilt)
×
844
                continue;
×
845

846
            SceneChannel sChan;
847
            sChan.m_universe = fixture->universe();
×
848
            sChan.m_fixture = fixture->id();
×
849
            sChan.m_channel = scv.channel;
×
850
            sChan.m_group = ch->group();
×
851
            sChan.m_subType = ch->controlByte();
×
852
            m_sceneChannels.append(sChan);
×
853
        }
854

855
        m_area->enableEFXPreview(false);
×
856
        // reset the area window as we're switching to relative
857
        m_area->setRangeWindow(QRectF());
×
858
        m_area->setPosition(QPointF(128, 128));
×
859
        m_area->repaint();
×
860
        m_scene->start(m_doc->masterTimer(), functionParent());
×
861

862
        if (preset->m_inputSource.isNull() == false)
×
863
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
864
    }
865
    else if (preset->m_type == VCXYPadPreset::Position)
×
866
    {
867
        m_area->enableEFXPreview(false);
×
868
        QRectF rect(QPointF(m_hRangeSlider->minimumPosition(), m_vRangeSlider->minimumPosition()),
×
869
                   QPointF(m_hRangeSlider->maximumPosition(), m_vRangeSlider->maximumPosition()));
×
870
        m_area->setRangeWindow(rect);
×
871
        m_area->setPosition(preset->m_dmxPos);
×
872
        m_area->repaint();
×
873
        if (preset->m_inputSource.isNull() == false)
×
874
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
875
        btn->blockSignals(true);
×
876
        btn->setDown(true);
×
877
        btn->blockSignals(false);
×
878
    }
879
    else if (preset->m_type == VCXYPadPreset::FixtureGroup)
×
880
    {
881
        QList<GroupHead> heads = preset->fixtureGroup();
×
882

883
        for (int i = 0; i < m_fixtures.count(); i++)
×
884
        {
885
            if (checked == false)
×
886
            {
887
                m_fixtures[i].setEnabled(true);
×
888
            }
889
            else
890
            {
891
                if (heads.contains(m_fixtures[i].head()))
×
892
                {
893
                    qDebug() << "Enabling head" << m_fixtures[i].head().fxi << m_fixtures[i].head().head;
×
894
                    m_fixtures[i].setEnabled(true);
×
895
                }
896
                else
897
                {
898
                    qDebug() << "Disabling head" << m_fixtures[i].head().fxi << m_fixtures[i].head().head;
×
899
                    m_fixtures[i].setEnabled(false);
×
900
                }
901
            }
902
        }
903
    }
904
}
905

906
void VCXYPad::slotEFXDurationChanged(uint duration)
×
907
{
908
    if (m_efx == NULL)
×
909
        return;
×
910

911
    m_area->setEFXInterval(duration);
×
912
}
913

914
FunctionParent VCXYPad::functionParent() const
×
915
{
916
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
917
}
918

919
/*********************************************************************
920
 * External input
921
 *********************************************************************/
922

923
void VCXYPad::updateFeedback()
6✔
924
{
925
    int Xfb = (int)SCALE(float(m_hSlider->value()), float(m_hSlider->minimum()),
6✔
926
                         float(m_hSlider->maximum()), float(0), float(UCHAR_MAX));
927
    sendFeedback(Xfb, panInputSourceId);
6✔
928

929
    int Yfb = (int)SCALE(float(m_vSlider->value()), float(m_vSlider->minimum()),
6✔
930
                         float(m_vSlider->maximum()), float(0), float(UCHAR_MAX));
931
    sendFeedback(Yfb, tiltInputSourceId);
6✔
932

933
/*
934
    for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
935
            it != m_presets.end(); ++it)
936
    {
937
        VCXYPadPreset* preset = it.value();
938
        if (preset->m_inputSource != NULL)
939
        {
940
            {
941
                QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
942
                if (preset->m_inputSource.isNull() == false)
943
                    sendFeedback(button->isDown() ?
944
                                 preset->m_inputSource->upperValue() :
945
                                 preset->m_inputSource->lowerValue(),
946
                                 preset->m_inputSource);
947
            }
948
        }
949
    }
950
*/
951
}
6✔
952

953
void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel,
×
954
                                     uchar value)
955
{
956
    /* Don't let input data through in design mode or if disabled */
957
    if (acceptsInput() == false)
×
958
        return;
×
959

960
    QPointF pt = m_area->position(false);
×
961
    quint32 pagedCh = (page() << 16) | channel;
×
962

963
    if (checkInputSource(universe, pagedCh, value, sender(), panInputSourceId))
×
964
    {
965
        if (m_efx == NULL)
×
966
        {
967
            qreal areaWidth = MAX_VALUE;
×
968
            qreal xOffset = 0;
×
969
            QRectF rangeWindow = m_area->rangeWindow();
×
970
            if (rangeWindow.isValid())
×
971
            {
972
                areaWidth = rangeWindow.width();
×
973
                xOffset = rangeWindow.x();
×
974
            }
975
            pt.setX(xOffset + SCALE(qreal(value), qreal(0), qreal(255),
×
976
                          qreal(0), areaWidth));
977
        }
978
        else
979
        {
980
            if (m_efx->isRunning() == false)
×
981
                return;
×
982
            m_hRangeSlider->setMinimumValue(value);
×
983
            slotRangeValueChanged();
×
984
            return;
×
985
        }
986
    }
987
    else if (checkInputSource(universe, pagedCh, value, sender(), tiltInputSourceId))
×
988
    {
989
        if (m_efx == NULL)
×
990
        {
991
            qreal yOffset = 0;
×
992
            qreal areaHeight = MAX_VALUE;
×
993
            QRectF rangeWindow = m_area->rangeWindow();
×
994
            if (rangeWindow.isValid())
×
995
            {
996
                areaHeight = rangeWindow.height();
×
997
                yOffset = rangeWindow.y();
×
998
            }
999
            if (invertedAppearance() == false)
×
1000
                pt.setY(yOffset + SCALE(qreal(value), qreal(0), qreal(255),
×
1001
                              qreal(0), areaHeight));
1002
            else
1003
                pt.setY(yOffset + SCALE(qreal(value), qreal(255), qreal(0),
×
1004
                              qreal(0), areaHeight));
1005
        }
1006
        else
1007
        {
1008
            if (m_efx->isRunning() == false)
×
1009
                return;
×
1010
            m_vRangeSlider->setMinimumValue(value);
×
1011
            slotRangeValueChanged();
×
1012
            return;
×
1013
        }
1014
    }
1015
    else if (checkInputSource(universe, pagedCh, value, sender(), widthInputSourceId))
×
1016
    {
1017
        if (m_efx != NULL && m_efx->isRunning())
×
1018
        {
1019
            m_hRangeSlider->setMaximumValue(value);
×
1020
            slotRangeValueChanged();
×
1021
        }
1022
        return;
×
1023
    }
1024
    else if (checkInputSource(universe, pagedCh, value, sender(), heightInputSourceId))
×
1025
    {
1026
        if (m_efx != NULL && m_efx->isRunning())
×
1027
        {
1028
            m_vRangeSlider->setMaximumValue(value);
×
1029
            slotRangeValueChanged();
×
1030
        }
1031
        return;
×
1032
    }
1033
    else
1034
    {
1035
        for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
×
1036
                it != m_presets.end(); ++it)
×
1037
        {
1038
            VCXYPadPreset *preset = it.value();
×
1039
            if (preset->m_inputSource != NULL &&
×
1040
                    preset->m_inputSource->universe() == universe &&
×
1041
                    preset->m_inputSource->channel() == pagedCh)
×
1042
            {
1043
                {
1044
                    QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
1045
                    button->click();
×
1046
                    return;
×
1047
                }
1048
            }
1049
        }
1050
    }
1051

1052
    m_inputValueChanged = true;
×
1053

1054
    m_area->setPosition(pt);
×
1055
    m_area->update();
×
1056
}
1057

1058
void VCXYPad::slotKeyPressed(const QKeySequence &keySequence)
×
1059
{
1060
    if (acceptsInput() == false)
×
1061
        return;
×
1062

1063
    for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
×
1064
            it != m_presets.end(); ++it)
×
1065
    {
1066
        VCXYPadPreset *preset = it.value();
×
1067
        if (preset->m_keySequence == keySequence)
×
1068
        {
1069
            QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
1070
            button->click();
×
1071
        }
1072
    }
1073
}
1074

1075
/*****************************************************************************
1076
 * QLC mode
1077
 *****************************************************************************/
1078

1079
void VCXYPad::slotModeChanged(Doc::Mode mode)
11✔
1080
{
1081
    if (mode == Doc::Operate && isDisabled() == false)
11✔
1082
    {
1083
        enableWidgetUI(true);
1✔
1084
    }
1085
    else
1086
    {
1087
        enableWidgetUI(false);
10✔
1088
    }
1089

1090
    VCWidget::slotModeChanged(mode);
11✔
1091
}
11✔
1092

1093
/*****************************************************************************
1094
 * Load & Save
1095
 *****************************************************************************/
1096

1097
bool VCXYPad::loadXML(QXmlStreamReader &root)
4✔
1098
{
1099
    bool visible = false;
4✔
1100
    int x = 0;
4✔
1101
    int y = 0;
4✔
1102
    int w = 0;
4✔
1103
    int h = 0;
4✔
1104

1105
    int xpos = 0;
4✔
1106
    int ypos = 0;
4✔
1107

1108
    if (root.name() != KXMLQLCVCXYPad)
4✔
1109
    {
1110
        qWarning() << Q_FUNC_INFO << "XY Pad node not found";
1✔
1111
        return false;
1✔
1112
    }
1113

1114
    /* Widget commons */
1115
    loadXMLCommon(root);
3✔
1116

1117
    QXmlStreamAttributes attrs = root.attributes();
6✔
1118

1119
    if (attrs.hasAttribute(KXMLQLCVCXYPadInvertedAppearance))
3✔
1120
    {
1121
        if (attrs.value(KXMLQLCVCXYPadInvertedAppearance).toString() == "0")
×
1122
            setInvertedAppearance(false);
×
1123
        else
1124
            setInvertedAppearance(true);
×
1125
    }
1126

1127
    // Sorted list for new presets
1128
    QList<VCXYPadPreset> newPresets;
3✔
1129

1130
    /* Children */
1131
    while (root.readNextStartElement())
15✔
1132
    {
1133
        if (root.name() == KXMLQLCWindowState)
12✔
1134
        {
1135
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
2✔
1136
        }
1137
        else if (root.name() == KXMLQLCVCWidgetAppearance)
10✔
1138
        {
1139
            loadXMLAppearance(root);
2✔
1140
        }
1141
        else if (root.name() == KXMLQLCVCXYPadPan)
8✔
1142
        {
1143
            xpos = root.attributes().value(KXMLQLCVCXYPadPosition).toString().toInt();
1✔
1144
            loadXMLSources(root, panInputSourceId);
1✔
1145
        }
1146
        else if (root.name() == KXMLQLCVCXYPadTilt)
7✔
1147
        {
1148
            ypos = root.attributes().value(KXMLQLCVCXYPadPosition).toString().toInt();
1✔
1149
            loadXMLSources(root, tiltInputSourceId);
1✔
1150
        }
1151
        else if (root.name() == KXMLQLCVCXYPadWidth)
6✔
1152
        {
1153
            loadXMLSources(root, widthInputSourceId);
×
1154
        }
1155
        else if (root.name() == KXMLQLCVCXYPadHeight)
6✔
1156
        {
1157
            loadXMLSources(root, heightInputSourceId);
×
1158
        }
1159
        else if (root.name() == KXMLQLCVCXYPadRangeWindow)
6✔
1160
        {
1161
            QXmlStreamAttributes wAttrs = root.attributes();
×
1162
            if (wAttrs.hasAttribute(KXMLQLCVCXYPadRangeHorizMin))
×
1163
                m_hRangeSlider->setMinimumPosition(wAttrs.value(KXMLQLCVCXYPadRangeHorizMin).toString().toInt());
×
1164
            if (wAttrs.hasAttribute(KXMLQLCVCXYPadRangeHorizMax))
×
1165
                m_hRangeSlider->setMaximumPosition(wAttrs.value(KXMLQLCVCXYPadRangeHorizMax).toString().toInt());
×
1166
            if (wAttrs.hasAttribute(KXMLQLCVCXYPadRangeVertMin))
×
1167
                m_vRangeSlider->setMinimumPosition(wAttrs.value(KXMLQLCVCXYPadRangeVertMin).toString().toInt());
×
1168
            if (wAttrs.hasAttribute(KXMLQLCVCXYPadRangeVertMax))
×
1169
                m_vRangeSlider->setMaximumPosition(wAttrs.value(KXMLQLCVCXYPadRangeVertMax).toString().toInt());
×
1170
            slotRangeValueChanged();
×
1171
            root.skipCurrentElement();
×
1172
        }
1173
        else if (root.name() == KXMLQLCVCXYPadPosition) // Legacy
6✔
1174
        {
1175
            QXmlStreamAttributes pAttrs = root.attributes();
4✔
1176
            xpos = pAttrs.value(KXMLQLCVCXYPadPositionX).toString().toInt();
2✔
1177
            ypos = pAttrs.value(KXMLQLCVCXYPadPositionY).toString().toInt();
2✔
1178
            root.skipCurrentElement();
2✔
1179
        }
1180
        else if (root.name() == KXMLQLCVCXYPadFixture)
4✔
1181
        {
1182
            VCXYPadFixture fxi(m_doc);
8✔
1183
            if (fxi.loadXML(root) == true)
4✔
1184
                appendFixture(fxi);
4✔
1185
        }
1186
        else if (root.name() == KXMLQLCVCXYPadPreset)
×
1187
        {
1188
            VCXYPadPreset preset(0xff);
×
1189
            if (preset.loadXML(root))
×
1190
                newPresets.insert(std::lower_bound(newPresets.begin(), newPresets.end(), preset), preset);
×
1191
        }
1192
        else
1193
        {
1194
            qWarning() << Q_FUNC_INFO << "Unknown XY Pad tag:" << root.name().toString();
×
1195
            root.skipCurrentElement();
×
1196
        }
1197
    }
1198

1199
    foreach (VCXYPadPreset const& preset, newPresets)
3✔
1200
        addPreset(preset);
×
1201

1202
    setGeometry(x, y, w, h);
3✔
1203
    show(); // Qt doesn't update the widget's geometry without this.
3✔
1204
    m_area->setPosition(QPointF(xpos, ypos));
3✔
1205

1206
    return true;
3✔
1207
}
1208

1209
bool VCXYPad::saveXML(QXmlStreamWriter *doc)
1✔
1210
{
1211
    Q_ASSERT(doc != NULL);
1✔
1212

1213
    /* VC XY Pad entry */
1214
    doc->writeStartElement(KXMLQLCVCXYPad);
1✔
1215

1216
    saveXMLCommon(doc);
1✔
1217

1218
    doc->writeAttribute(KXMLQLCVCXYPadInvertedAppearance, QString::number(invertedAppearance()));
1✔
1219

1220
    /* Window state */
1221
    saveXMLWindowState(doc);
1✔
1222

1223
    /* Appearance */
1224
    saveXMLAppearance(doc);
1✔
1225

1226
    /* Fixtures */
1227
    foreach (VCXYPadFixture fixture, m_fixtures)
5✔
1228
        fixture.saveXML(doc);
2✔
1229

1230
    /* Current XY position */
1231
    QPointF pt(m_area->position(false));
1✔
1232

1233
    /* Custom range window */
1234
    if (m_hRangeSlider->minimumPosition() != 0 ||
1✔
1235
        m_hRangeSlider->maximumPosition() != 256 ||
1✔
1236
        m_vRangeSlider->minimumPosition() != 0 ||
3✔
1237
        m_vRangeSlider->maximumPosition() != 256)
1✔
1238
    {
1239
        doc->writeStartElement(KXMLQLCVCXYPadRangeWindow);
×
1240
        doc->writeAttribute(KXMLQLCVCXYPadRangeHorizMin, QString::number(m_hRangeSlider->minimumPosition()));
×
1241
        doc->writeAttribute(KXMLQLCVCXYPadRangeHorizMax, QString::number(m_hRangeSlider->maximumPosition()));
×
1242
        doc->writeAttribute(KXMLQLCVCXYPadRangeVertMin, QString::number(m_vRangeSlider->minimumPosition()));
×
1243
        doc->writeAttribute(KXMLQLCVCXYPadRangeVertMax, QString::number(m_vRangeSlider->maximumPosition()));
×
1244
        doc->writeEndElement();
×
1245
    }
1246

1247
    /* Pan */
1248
    doc->writeStartElement(KXMLQLCVCXYPadPan);
1✔
1249
    doc->writeAttribute(KXMLQLCVCXYPadPosition, QString::number(int(pt.x())));
1✔
1250
    saveXMLInput(doc, inputSource(panInputSourceId));
1✔
1251
    doc->writeEndElement();
1✔
1252

1253
    /* Tilt */
1254
    doc->writeStartElement(KXMLQLCVCXYPadTilt);
1✔
1255
    doc->writeAttribute(KXMLQLCVCXYPadPosition, QString::number(int(pt.y())));
1✔
1256
    saveXMLInput(doc, inputSource(tiltInputSourceId));
1✔
1257
    doc->writeEndElement();
1✔
1258

1259
    /* Width */
1260
    QSharedPointer<QLCInputSource> wSrc = inputSource(widthInputSourceId);
2✔
1261
    if (!wSrc.isNull() && wSrc->isValid())
1✔
1262
    {
1263
        doc->writeStartElement(KXMLQLCVCXYPadWidth);
1✔
1264
        saveXMLInput(doc, wSrc);
1✔
1265
        doc->writeEndElement();
1✔
1266
    }
1267

1268
    /* Height */
1269
    QSharedPointer<QLCInputSource> hSrc = inputSource(heightInputSourceId);
1✔
1270
    if (!hSrc.isNull() && hSrc->isValid())
1✔
1271
    {
1272
        doc->writeStartElement(KXMLQLCVCXYPadHeight);
1✔
1273
        saveXMLInput(doc, hSrc);
1✔
1274
        doc->writeEndElement();
1✔
1275
    }
1276

1277
    // Presets
1278
    foreach (VCXYPadPreset *preset, presets())
2✔
1279
        preset->saveXML(doc);
×
1280

1281
    /* End the >XYPad> tag */
1282
    doc->writeEndElement();
1✔
1283

1284
    return true;
2✔
1285
}
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