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

mcallegari / qlcplus / 8530698081

02 Apr 2024 11:14PM UTC coverage: 32.084% (+0.006%) from 32.078%
8530698081

Pull #1528

github

web-flow
Merge 5c495ac52 into 8337821bf
Pull Request #1528: Update qlcplus_fr_FR.ts

15389 of 47965 relevant lines covered (32.08%)

22934.26 hits per line

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

37.44
/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
void VCXYPad::slotPresetClicked(bool checked)
×
694
{
695
    if (mode() == Doc::Design)
×
696
        return;
×
697

698
    QPushButton *btn = qobject_cast<QPushButton*>(sender());
×
699
    VCXYPadPreset *preset = m_presets[btn];
×
700

701
    Q_ASSERT(preset != NULL);
×
702

703
    // stop any previously started EFX
704
    if (m_efx != NULL && m_efx->isRunning())
×
705
    {
706
        disconnect(m_efx, SIGNAL(durationChanged(uint)), this, SLOT(slotEFXDurationChanged(uint)));
×
707

708
        m_efx->stopAndWait();
×
709
        m_efx = NULL;
×
710
        m_efxStartXOverrideId = Function::invalidAttributeId();
×
711
        m_efxStartYOverrideId = Function::invalidAttributeId();
×
712
        m_efxWidthOverrideId = Function::invalidAttributeId();
×
713
        m_efxHeightOverrideId = Function::invalidAttributeId();
×
714
    }
715

716
    // stop any previously started Scene
717
    if (m_scene != NULL)
×
718
    {
719
        m_scene->stop(functionParent());
×
720
        m_scene = NULL;
×
721
        foreach (QSharedPointer<GenericFader> fader, m_fadersMap.values())
×
722
        {
723
            if (!fader.isNull())
×
724
                fader->requestDelete();
×
725
        }
726
        m_fadersMap.clear();
×
727
    }
728

729
    // deactivate all previously activated buttons first
730
    for (QHash<QWidget *, VCXYPadPreset *>::iterator it = m_presets.begin();
×
731
            it != m_presets.end(); ++it)
×
732
    {
733
        QPushButton* cBtn = reinterpret_cast<QPushButton*>(it.key());
×
734
        VCXYPadPreset *cPr = it.value();
×
735
        if (preset->m_id == cPr->m_id)
×
736
            continue;
×
737

738
        cBtn->blockSignals(true);
×
739
        if (preset->m_type == VCXYPadPreset::FixtureGroup)
×
740
        {
741
            if (cPr->m_type == VCXYPadPreset::FixtureGroup &&
×
742
                cBtn->isChecked() == true)
×
743
            {
744
                cBtn->setChecked(false);
×
745
                if (cPr->m_inputSource.isNull() == false)
×
746
                    sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
747
            }
748
        }
749
        else if (cPr->m_type == VCXYPadPreset::EFX ||
×
750
            cPr->m_type == VCXYPadPreset::Scene)
×
751
        {
752
            if (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
760
        {
761
            if (cBtn->isDown() == true)
×
762
            {
763
                cBtn->setDown(false);
×
764
                if (cPr->m_inputSource.isNull() == false)
×
765
                    sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
766
            }
767
        }
768
        cBtn->blockSignals(false);
×
769
        if (cPr->m_inputSource.isNull() == false)
×
770
            sendFeedback(cPr->m_inputSource->feedbackValue(QLCInputFeedback::LowerValue), cPr->m_inputSource);
×
771
    }
772

773
    if (preset->m_type == VCXYPadPreset::EFX)
×
774
    {
775
        if (checked == false)
×
776
        {
777
            m_area->enableEFXPreview(false);
×
778
            return;
×
779
        }
780

781
        Function *f = m_doc->function(preset->m_funcID);
×
782
        if (f == NULL || f->type() != Function::EFXType)
×
783
            return;
×
784
        m_efx = qobject_cast<EFX*>(f);
×
785

786
        QRectF rect(QPointF(m_hRangeSlider->minimumPosition(), m_vRangeSlider->minimumPosition()),
×
787
                   QPointF(m_hRangeSlider->maximumPosition(), m_vRangeSlider->maximumPosition()));
×
788
        m_area->setRangeWindow(rect);
×
789
        if (rect.isValid())
×
790
        {
791
            m_efxStartXOverrideId = m_efx->requestAttributeOverride(EFX::XOffset, rect.x() + rect.width() / 2);
×
792
            m_efxStartYOverrideId = m_efx->requestAttributeOverride(EFX::YOffset, rect.y() + rect.height() / 2);
×
793
            m_efxWidthOverrideId = m_efx->requestAttributeOverride(EFX::Width, rect.width() / 2);
×
794
            m_efxHeightOverrideId = m_efx->requestAttributeOverride(EFX::Height, rect.height() / 2);
×
795
        }
796

797
        QPolygonF polygon;
×
798
        m_efx->preview(polygon);
×
799

800
        QVector <QPolygonF> fixturePoints;
×
801
        m_efx->previewFixtures(fixturePoints);
×
802

803
        m_area->enableEFXPreview(true);
×
804
        m_area->setEFXPolygons(polygon, fixturePoints);
×
805
        m_area->setEFXInterval(m_efx->duration());
×
806
        m_efx->start(m_doc->masterTimer(), functionParent());
×
807

808
        connect(m_efx, SIGNAL(durationChanged(uint)), this, SLOT(slotEFXDurationChanged(uint)));
×
809

810
        if (preset->m_inputSource.isNull() == false)
×
811
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
812
    }
813
    else if (preset->m_type == VCXYPadPreset::Scene)
×
814
    {
815
        if (checked == false)
×
816
            return;
×
817

818
        Function *f = m_doc->function(preset->m_funcID);
×
819
        if (f == NULL || f->type() != Function::SceneType)
×
820
            return;
×
821

822
        m_scene = qobject_cast<Scene*>(f);
×
823
        m_sceneChannels.clear();
×
824

825
        foreach (SceneValue scv, m_scene->values())
×
826
        {
827
            Fixture *fixture = m_doc->fixture(scv.fxi);
×
828
            if (fixture == NULL)
×
829
                continue;
×
830
            const QLCChannel *ch = fixture->channel(scv.channel);
×
831
            if (ch == NULL)
×
832
                continue;
×
833
            if (ch->group() != QLCChannel::Pan && ch->group() != QLCChannel::Tilt)
×
834
                continue;
×
835

836
            SceneChannel sChan;
837
            sChan.m_universe = fixture->universe();
×
838
            sChan.m_fixture = fixture->id();
×
839
            sChan.m_channel = scv.channel;
×
840
            sChan.m_group = ch->group();
×
841
            sChan.m_subType = ch->controlByte();
×
842
            m_sceneChannels.append(sChan);
×
843
        }
844

845
        m_area->enableEFXPreview(false);
×
846
        // reset the area window as we're switching to relative
847
        m_area->setRangeWindow(QRectF());
×
848
        m_area->setPosition(QPointF(128, 128));
×
849
        m_area->repaint();
×
850
        m_scene->start(m_doc->masterTimer(), functionParent());
×
851

852
        if (preset->m_inputSource.isNull() == false)
×
853
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
854
    }
855
    else if (preset->m_type == VCXYPadPreset::Position)
×
856
    {
857
        m_area->enableEFXPreview(false);
×
858
        QRectF rect(QPointF(m_hRangeSlider->minimumPosition(), m_vRangeSlider->minimumPosition()),
×
859
                   QPointF(m_hRangeSlider->maximumPosition(), m_vRangeSlider->maximumPosition()));
×
860
        m_area->setRangeWindow(rect);
×
861
        m_area->setPosition(preset->m_dmxPos);
×
862
        m_area->repaint();
×
863
        if (preset->m_inputSource.isNull() == false)
×
864
            sendFeedback(preset->m_inputSource->feedbackValue(QLCInputFeedback::UpperValue), preset->m_inputSource);
×
865
        btn->blockSignals(true);
×
866
        btn->setDown(true);
×
867
        btn->blockSignals(false);
×
868
    }
869
    else if (preset->m_type == VCXYPadPreset::FixtureGroup)
×
870
    {
871
        QList<GroupHead> heads = preset->fixtureGroup();
×
872

873
        for (int i = 0; i < m_fixtures.count(); i++)
×
874
        {
875
            if (checked == false)
×
876
            {
877
                m_fixtures[i].setEnabled(true);
×
878
            }
879
            else
880
            {
881
                if (heads.contains(m_fixtures[i].head()))
×
882
                {
883
                    qDebug() << "Enabling head" << m_fixtures[i].head().fxi << m_fixtures[i].head().head;
×
884
                    m_fixtures[i].setEnabled(true);
×
885
                }
886
                else
887
                {
888
                    qDebug() << "Disabling head" << m_fixtures[i].head().fxi << m_fixtures[i].head().head;
×
889
                    m_fixtures[i].setEnabled(false);
×
890
                }
891
            }
892
        }
893
    }
894
}
895

896
void VCXYPad::slotEFXDurationChanged(uint duration)
×
897
{
898
    if (m_efx == NULL)
×
899
        return;
×
900

901
    m_area->setEFXInterval(duration);
×
902
}
903

904
FunctionParent VCXYPad::functionParent() const
×
905
{
906
    return FunctionParent(FunctionParent::ManualVCWidget, id());
×
907
}
908

909
/*********************************************************************
910
 * External input
911
 *********************************************************************/
912

913
void VCXYPad::updateFeedback()
6✔
914
{
915
    int Xfb = (int)SCALE(float(m_hSlider->value()), float(m_hSlider->minimum()),
6✔
916
                         float(m_hSlider->maximum()), float(0), float(UCHAR_MAX));
917
    sendFeedback(Xfb, panInputSourceId);
6✔
918

919
    int Yfb = (int)SCALE(float(m_vSlider->value()), float(m_vSlider->minimum()),
6✔
920
                         float(m_vSlider->maximum()), float(0), float(UCHAR_MAX));
921
    sendFeedback(Yfb, tiltInputSourceId);
6✔
922

923
/*
924
    for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
925
            it != m_presets.end(); ++it)
926
    {
927
        VCXYPadPreset* preset = it.value();
928
        if (preset->m_inputSource != NULL)
929
        {
930
            {
931
                QPushButton* button = reinterpret_cast<QPushButton*>(it.key());
932
                if (preset->m_inputSource.isNull() == false)
933
                    sendFeedback(button->isDown() ?
934
                                 preset->m_inputSource->upperValue() :
935
                                 preset->m_inputSource->lowerValue(),
936
                                 preset->m_inputSource);
937
            }
938
        }
939
    }
940
*/
941
}
6✔
942

943
void VCXYPad::slotInputValueChanged(quint32 universe, quint32 channel,
×
944
                                     uchar value)
945
{
946
    /* Don't let input data through in design mode or if disabled */
947
    if (acceptsInput() == false)
×
948
        return;
×
949

950
    QPointF pt = m_area->position(false);
×
951
    quint32 pagedCh = (page() << 16) | channel;
×
952

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

1042
    m_inputValueChanged = true;
×
1043

1044
    m_area->setPosition(pt);
×
1045
    m_area->update();
×
1046
}
1047

1048
void VCXYPad::slotKeyPressed(const QKeySequence &keySequence)
×
1049
{
1050
    if (acceptsInput() == false)
×
1051
        return;
×
1052

1053
    for (QHash<QWidget*, VCXYPadPreset*>::iterator it = m_presets.begin();
×
1054
            it != m_presets.end(); ++it)
×
1055
    {
1056
        VCXYPadPreset *preset = it.value();
×
1057
        if (preset->m_keySequence == keySequence)
×
1058
        {
1059
            QPushButton *button = reinterpret_cast<QPushButton*>(it.key());
×
1060
            button->click();
×
1061
        }
1062
    }
1063
}
1064

1065
/*****************************************************************************
1066
 * QLC mode
1067
 *****************************************************************************/
1068

1069
void VCXYPad::slotModeChanged(Doc::Mode mode)
11✔
1070
{
1071
    if (mode == Doc::Operate && isDisabled() == false)
11✔
1072
    {
1073
        enableWidgetUI(true);
1✔
1074
    }
1075
    else
1076
    {
1077
        enableWidgetUI(false);
10✔
1078
    }
1079

1080
    VCWidget::slotModeChanged(mode);
11✔
1081
}
11✔
1082

1083
/*****************************************************************************
1084
 * Load & Save
1085
 *****************************************************************************/
1086

1087
bool VCXYPad::loadXML(QXmlStreamReader &root)
4✔
1088
{
1089
    bool visible = false;
4✔
1090
    int x = 0;
4✔
1091
    int y = 0;
4✔
1092
    int w = 0;
4✔
1093
    int h = 0;
4✔
1094

1095
    int xpos = 0;
4✔
1096
    int ypos = 0;
4✔
1097

1098
    if (root.name() != KXMLQLCVCXYPad)
4✔
1099
    {
1100
        qWarning() << Q_FUNC_INFO << "XY Pad node not found";
1✔
1101
        return false;
1✔
1102
    }
1103

1104
    /* Widget commons */
1105
    loadXMLCommon(root);
3✔
1106

1107
    QXmlStreamAttributes attrs = root.attributes();
6✔
1108

1109
    if (attrs.hasAttribute(KXMLQLCVCXYPadInvertedAppearance))
3✔
1110
    {
1111
        if (attrs.value(KXMLQLCVCXYPadInvertedAppearance).toString() == "0")
×
1112
            setInvertedAppearance(false);
×
1113
        else
1114
            setInvertedAppearance(true);
×
1115
    }
1116

1117
    // Sorted list for new presets
1118
    QList<VCXYPadPreset> newPresets;
3✔
1119

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

1189
    foreach (VCXYPadPreset const& preset, newPresets)
3✔
1190
        addPreset(preset);
×
1191

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

1196
    return true;
3✔
1197
}
1198

1199
bool VCXYPad::saveXML(QXmlStreamWriter *doc)
1✔
1200
{
1201
    Q_ASSERT(doc != NULL);
1✔
1202

1203
    /* VC XY Pad entry */
1204
    doc->writeStartElement(KXMLQLCVCXYPad);
1✔
1205

1206
    saveXMLCommon(doc);
1✔
1207

1208
    doc->writeAttribute(KXMLQLCVCXYPadInvertedAppearance, QString::number(invertedAppearance()));
1✔
1209

1210
    /* Window state */
1211
    saveXMLWindowState(doc);
1✔
1212

1213
    /* Appearance */
1214
    saveXMLAppearance(doc);
1✔
1215

1216
    /* Fixtures */
1217
    foreach (VCXYPadFixture fixture, m_fixtures)
5✔
1218
        fixture.saveXML(doc);
2✔
1219

1220
    /* Current XY position */
1221
    QPointF pt(m_area->position(false));
1✔
1222

1223
    /* Custom range window */
1224
    if (m_hRangeSlider->minimumPosition() != 0 ||
1✔
1225
        m_hRangeSlider->maximumPosition() != 256 ||
1✔
1226
        m_vRangeSlider->minimumPosition() != 0 ||
3✔
1227
        m_vRangeSlider->maximumPosition() != 256)
1✔
1228
    {
1229
        doc->writeStartElement(KXMLQLCVCXYPadRangeWindow);
×
1230
        doc->writeAttribute(KXMLQLCVCXYPadRangeHorizMin, QString::number(m_hRangeSlider->minimumPosition()));
×
1231
        doc->writeAttribute(KXMLQLCVCXYPadRangeHorizMax, QString::number(m_hRangeSlider->maximumPosition()));
×
1232
        doc->writeAttribute(KXMLQLCVCXYPadRangeVertMin, QString::number(m_vRangeSlider->minimumPosition()));
×
1233
        doc->writeAttribute(KXMLQLCVCXYPadRangeVertMax, QString::number(m_vRangeSlider->maximumPosition()));
×
1234
        doc->writeEndElement();
×
1235
    }
1236

1237
    /* Pan */
1238
    doc->writeStartElement(KXMLQLCVCXYPadPan);
1✔
1239
    doc->writeAttribute(KXMLQLCVCXYPadPosition, QString::number(int(pt.x())));
1✔
1240
    saveXMLInput(doc, inputSource(panInputSourceId));
1✔
1241
    doc->writeEndElement();
1✔
1242

1243
    /* Tilt */
1244
    doc->writeStartElement(KXMLQLCVCXYPadTilt);
1✔
1245
    doc->writeAttribute(KXMLQLCVCXYPadPosition, QString::number(int(pt.y())));
1✔
1246
    saveXMLInput(doc, inputSource(tiltInputSourceId));
1✔
1247
    doc->writeEndElement();
1✔
1248

1249
    /* Width */
1250
    QSharedPointer<QLCInputSource> wSrc = inputSource(widthInputSourceId);
2✔
1251
    if (!wSrc.isNull() && wSrc->isValid())
1✔
1252
    {
1253
        doc->writeStartElement(KXMLQLCVCXYPadWidth);
1✔
1254
        saveXMLInput(doc, wSrc);
1✔
1255
        doc->writeEndElement();
1✔
1256
    }
1257

1258
    /* Height */
1259
    QSharedPointer<QLCInputSource> hSrc = inputSource(heightInputSourceId);
1✔
1260
    if (!hSrc.isNull() && hSrc->isValid())
1✔
1261
    {
1262
        doc->writeStartElement(KXMLQLCVCXYPadHeight);
1✔
1263
        saveXMLInput(doc, hSrc);
1✔
1264
        doc->writeEndElement();
1✔
1265
    }
1266

1267
    // Presets
1268
    foreach (VCXYPadPreset *preset, presets())
2✔
1269
        preset->saveXML(doc);
×
1270

1271
    /* End the >XYPad> tag */
1272
    doc->writeEndElement();
1✔
1273

1274
    return true;
2✔
1275
}
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