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

mcallegari / qlcplus / 19144422256

06 Nov 2025 05:33PM UTC coverage: 34.256% (-0.1%) from 34.358%
19144422256

push

github

mcallegari
Back to 5.1.0 debug

17718 of 51723 relevant lines covered (34.26%)

19528.23 hits per line

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

0.0
/ui/src/virtualconsole/vcxypadproperties.cpp
1
/*
2
  Q Light Controller
3
  vcxypadproperties.h
4

5
  Copyright (C) Stefan Krumm, Heikki Junnila
6

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

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

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

20
#include <QTreeWidgetItem>
21
#include <QTreeWidget>
22
#include <QMessageBox>
23
#include <QHeaderView>
24
#include <QSettings>
25
#include <QDebug>
26
#include <QAction>
27

28
#include "qlcfixturemode.h"
29
#include "qlcchannel.h"
30
#include "qlcmacros.h"
31

32
#include "vcxypadfixtureeditor.h"
33
#include "inputselectionwidget.h"
34
#include "vcxypadproperties.h"
35
#include "functionselection.h"
36
#include "fixtureselection.h"
37
#include "vcxypadfixture.h"
38
#include "vcxypadpreset.h"
39
#include "vcxypadarea.h"
40
#include "vcxypad.h"
41
#include "apputil.h"
42
#include "scene.h"
43
#include "doc.h"
44
#include "efx.h"
45

46
#define SETTINGS_GEOMETRY "vcxypad/geometry"
47

48
#define KColumnFixture   0
49
#define KColumnXAxis     1
50
#define KColumnYAxis     2
51

52
/****************************************************************************
53
 * Initialization
54
 ****************************************************************************/
55

56
VCXYPadProperties::VCXYPadProperties(VCXYPad* xypad, Doc* doc)
×
57
    : QDialog(xypad)
58
    , m_xypad(xypad)
×
59
    , m_doc(doc)
×
60
{
61
    Q_ASSERT(doc != NULL);
×
62
    Q_ASSERT(xypad != NULL);
×
63

64
    setupUi(this);
×
65

66
    // IDs 0-15 are reserved for XYPad base controls
67
    m_lastAssignedID = 15;
×
68

69
    QAction* action = new QAction(this);
×
70
    action->setShortcut(QKeySequence(QKeySequence::Close));
×
71
    connect(action, SIGNAL(triggered(bool)), this, SLOT(reject()));
×
72
    addAction(action);
×
73

74
    /********************************************************************
75
     * General page
76
     ********************************************************************/
77

78
    m_nameEdit->setText(m_xypad->caption());
×
79

80
    if (m_xypad->invertedAppearance() == true)
×
81
        m_YInvertedRadio->setChecked(true);
×
82

83
    m_panInputWidget = new InputSelectionWidget(m_doc, this);
×
84
    m_panInputWidget->setTitle(tr("Pan / Horizontal Axis"));
×
85
    m_panInputWidget->setKeyInputVisibility(false);
×
86
    m_panInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::panInputSourceId));
×
87
    m_panInputWidget->setWidgetPage(m_xypad->page());
×
88
    m_panInputWidget->emitOddValues(true);
×
89
    m_panInputWidget->show();
×
90
    m_extInputLayout->addWidget(m_panInputWidget);
×
91
    connect(m_panInputWidget, SIGNAL(autoDetectToggled(bool)),
×
92
            this, SLOT(slotPanAutoDetectToggled(bool)));
93
    connect(m_panInputWidget, SIGNAL(inputValueChanged(quint32,quint32)),
×
94
            this, SLOT(slotPanInputValueChanged(quint32,quint32)));
95

96
    m_panFineInputWidget = new InputSelectionWidget(m_doc, this);
×
97
    m_panFineInputWidget->setTitle(tr("Pan Fine"));
×
98
    m_panFineInputWidget->setKeyInputVisibility(false);
×
99
    m_panFineInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::panFineInputSourceId));
×
100
    m_panFineInputWidget->setWidgetPage(m_xypad->page());
×
101
    m_panFineInputWidget->emitOddValues(true);
×
102
    m_panFineInputWidget->show();
×
103
    m_extFineInputLayout->addWidget(m_panFineInputWidget);
×
104
    connect(m_panFineInputWidget, SIGNAL(autoDetectToggled(bool)),
×
105
            this, SLOT(slotPanFineAutoDetectToggled(bool)));
106
    connect(m_panFineInputWidget, SIGNAL(inputValueChanged(quint32,quint32)),
×
107
            this, SLOT(slotPanFineInputValueChanged(quint32,quint32)));
108

109
    m_tiltInputWidget = new InputSelectionWidget(m_doc, this);
×
110
    m_tiltInputWidget->setTitle(tr("Tilt / Vertical Axis"));
×
111
    m_tiltInputWidget->setKeyInputVisibility(false);
×
112
    m_tiltInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::tiltInputSourceId));
×
113
    m_tiltInputWidget->setWidgetPage(m_xypad->page());
×
114
    m_tiltInputWidget->emitOddValues(true);
×
115
    m_tiltInputWidget->show();
×
116
    m_extInputLayout->addWidget(m_tiltInputWidget);
×
117
    connect(m_tiltInputWidget, SIGNAL(autoDetectToggled(bool)),
×
118
            this, SLOT(slotTiltAutoDetectToggled(bool)));
119
    connect(m_tiltInputWidget, SIGNAL(inputValueChanged(quint32,quint32)),
×
120
            this, SLOT(slotTiltInputValueChanged(quint32,quint32)));
121

122
    m_tiltFineInputWidget = new InputSelectionWidget(m_doc, this);
×
123
    m_tiltFineInputWidget->setTitle(tr("Tilt Fine"));
×
124
    m_tiltFineInputWidget->setKeyInputVisibility(false);
×
125
    m_tiltFineInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::tiltFineInputSourceId));
×
126
    m_tiltFineInputWidget->setWidgetPage(m_xypad->page());
×
127
    m_tiltFineInputWidget->emitOddValues(true);
×
128
    m_tiltFineInputWidget->show();
×
129
    m_extFineInputLayout->addWidget(m_tiltFineInputWidget);
×
130
    connect(m_tiltFineInputWidget, SIGNAL(autoDetectToggled(bool)),
×
131
            this, SLOT(slotTiltFineAutoDetectToggled(bool)));
132
    connect(m_tiltFineInputWidget, SIGNAL(inputValueChanged(quint32,quint32)),
×
133
            this, SLOT(slotTiltFineInputValueChanged(quint32,quint32)));
134

135
    m_widthInputWidget = new InputSelectionWidget(m_doc, this);
×
136
    m_widthInputWidget->setTitle(tr("Width"));
×
137
    m_widthInputWidget->setKeyInputVisibility(false);
×
138
    m_widthInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::widthInputSourceId));
×
139
    m_widthInputWidget->setWidgetPage(m_xypad->page());
×
140
    m_widthInputWidget->show();
×
141
    m_sizeInputLayout->addWidget(m_widthInputWidget);
×
142

143
    m_heightInputWidget = new InputSelectionWidget(m_doc, this);
×
144
    m_heightInputWidget->setTitle(tr("Height"));
×
145
    m_heightInputWidget->setKeyInputVisibility(false);
×
146
    m_heightInputWidget->setInputSource(m_xypad->inputSource(VCXYPad::heightInputSourceId));
×
147
    m_heightInputWidget->setWidgetPage(m_xypad->page());
×
148
    m_heightInputWidget->show();
×
149
    m_sizeInputLayout->addWidget(m_heightInputWidget);
×
150

151
    /********************************************************************
152
     * Fixtures page
153
     ********************************************************************/
154

155
    slotSelectionChanged(NULL);
×
156
    fillFixturesTree();
×
157

158
    connect(m_percentageRadio, SIGNAL(clicked(bool)),
×
159
            this, SLOT(slotPercentageRadioChecked()));
160
    connect(m_degreesRadio, SIGNAL(clicked(bool)),
×
161
            this, SLOT(slotDegreesRadioChecked()));
162
    connect(m_dmxRadio, SIGNAL(clicked(bool)),
×
163
            this, SLOT(slotDMXRadioChecked()));
164

165
    /********************************************************************
166
     * Presets page
167
     ********************************************************************/
168

169
    m_presetInputWidget = new InputSelectionWidget(m_doc, this);
×
170
    m_presetInputWidget->setCustomFeedbackVisibility(true);
×
171
    m_presetInputWidget->setWidgetPage(m_xypad->page());
×
172
    m_presetInputWidget->show();
×
173
    m_presetInputLayout->addWidget(m_presetInputWidget);
×
174

175
    connect(m_presetInputWidget, SIGNAL(inputValueChanged(quint32,quint32)),
×
176
            this, SLOT(slotInputValueChanged(quint32,quint32)));
177
    connect(m_presetInputWidget, SIGNAL(keySequenceChanged(QKeySequence)),
×
178
            this, SLOT(slotKeySequenceChanged(QKeySequence)));
179

180
    connect(m_addPositionButton, SIGNAL(clicked(bool)),
×
181
            this, SLOT(slotAddPositionClicked()));
182
    connect(m_addEfxButton, SIGNAL(clicked(bool)),
×
183
            this, SLOT(slotAddEFXClicked()));
184
    connect(m_addSceneButton, SIGNAL(clicked(bool)),
×
185
            this, SLOT(slotAddSceneClicked()));
186
    connect(m_addFxGroupButton, SIGNAL(clicked(bool)),
×
187
            this, SLOT(slotAddFixtureGroupClicked()));
188
    connect(m_removePresetButton, SIGNAL(clicked()),
×
189
            this, SLOT(slotRemovePresetClicked()));
190
    connect(m_moveUpPresetButton, SIGNAL(clicked()),
×
191
            this, SLOT(slotMoveUpPresetClicked()));
192
    connect(m_moveDownPresetButton, SIGNAL(clicked()),
×
193
            this, SLOT(slotMoveDownPresetClicked()));
194
    connect(m_presetNameEdit, SIGNAL(textEdited(QString const&)),
×
195
            this, SLOT(slotPresetNameEdited(QString const&)));
196
    connect(m_presetsTree, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
×
197
            this, SLOT(slotPresetSelectionChanged()));
198

199
    m_xyArea = new VCXYPadArea(this);
×
200
    //m_xyArea->setFixedSize(140, 140);
201
    m_xyArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
×
202
    m_xyArea->setMode(Doc::Operate);
×
203
    m_presetLayout->addWidget(m_xyArea);
×
204
    connect(m_xyArea, SIGNAL(positionChanged(QPointF)),
×
205
            this, SLOT(slotXYPadPositionChanged(QPointF)));
206

207
    foreach (const VCXYPadPreset *preset, m_xypad->presets())
×
208
    {
209
        m_presetList.append(new VCXYPadPreset(*preset));
×
210
        if (preset->m_id > m_lastAssignedID)
×
211
            m_lastAssignedID = preset->m_id;
×
212
    }
×
213

214
    updatePresetsTree();
×
215

216
    QSettings settings;
×
217
    QVariant var = settings.value(SETTINGS_GEOMETRY);
×
218
    if (var.isValid() == true)
×
219
        restoreGeometry(var.toByteArray());
×
220
    AppUtil::ensureWidgetIsVisible(this);
×
221

222
    m_doc->masterTimer()->registerDMXSource(this);
×
223
}
×
224

225
VCXYPadProperties::~VCXYPadProperties()
×
226
{
227
    QSettings settings;
×
228
    settings.setValue(SETTINGS_GEOMETRY, saveGeometry());
×
229
    m_doc->masterTimer()->unregisterDMXSource(this);
×
230
    foreach (QSharedPointer<GenericFader> fader, m_fadersMap)
×
231
    {
232
        if (!fader.isNull())
×
233
            fader->requestDelete();
×
234
    }
×
235
    m_fadersMap.clear();
×
236

237
    delete m_presetInputWidget;
×
238
}
×
239

240
/****************************************************************************
241
 * Fixtures page
242
 ****************************************************************************/
243

244
void VCXYPadProperties::fillFixturesTree()
×
245
{
246
    m_tree->clear();
×
247

248
    QListIterator <VCXYPadFixture> it(m_xypad->fixtures());
×
249
    while (it.hasNext() == true)
×
250
        updateFixtureItem(new QTreeWidgetItem(m_tree), it.next());
×
251
    m_tree->setCurrentItem(m_tree->topLevelItem(0));
×
252
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
253
}
×
254

255
void VCXYPadProperties::updateFixturesTree(VCXYPadFixture::DisplayMode mode)
×
256
{
257
    for (int i = 0; i < m_tree->topLevelItemCount(); i++)
×
258
    {
259
        QTreeWidgetItem *item = m_tree->topLevelItem(i);
×
260
        QVariant var(item->data(KColumnFixture, Qt::UserRole));
×
261
        VCXYPadFixture fx = VCXYPadFixture(m_doc, var);
×
262
        fx.setDisplayMode(mode);
×
263
        updateFixtureItem(item, fx);
×
264
    }
×
265
}
×
266

267
void VCXYPadProperties::updateFixtureItem(QTreeWidgetItem* item,
×
268
                                          const VCXYPadFixture& fxi)
269
{
270
    Q_ASSERT(item != NULL);
×
271

272
    item->setText(KColumnFixture, fxi.name());
×
273
    item->setText(KColumnXAxis, fxi.xBrief());
×
274
    item->setText(KColumnYAxis, fxi.yBrief());
×
275
    item->setData(KColumnFixture, Qt::UserRole, QVariant(fxi));
×
276
}
×
277

278
QList <VCXYPadFixture> VCXYPadProperties::selectedFixtures() const
×
279
{
280
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
281
    QList <VCXYPadFixture> list;
×
282

283
    /* Put all selected fixtures to a list and return it */
284
    while (it.hasNext() == true)
×
285
        list << VCXYPadFixture(m_doc, it.next()->data(KColumnFixture, Qt::UserRole));
×
286

287
    return list;
×
288
}
×
289

290
QTreeWidgetItem* VCXYPadProperties::fixtureItem(const VCXYPadFixture& fxi)
×
291
{
292
    QTreeWidgetItemIterator it(m_tree);
×
293
    while (*it != NULL)
×
294
    {
295
        QVariant var((*it)->data(KColumnFixture, Qt::UserRole));
×
296
        VCXYPadFixture another(m_doc, var);
×
297
        if (fxi.head() == another.head())
×
298
            return *it;
×
299
        else
300
            ++it;
×
301
    }
×
302

303
    return NULL;
×
304
}
×
305

306
void VCXYPadProperties::removeFixtureItem(GroupHead const & head)
×
307
{
308
    QTreeWidgetItemIterator it(m_tree);
×
309
    while (*it != NULL)
×
310
    {
311
        QVariant var((*it)->data(KColumnFixture, Qt::UserRole));
×
312
        VCXYPadFixture fxi(m_doc, var);
×
313
        if (fxi.head() == head)
×
314
        {
315
            delete (*it);
×
316
            break;
×
317
        }
318

319
        ++it;
×
320
    }
×
321
}
×
322

323
void VCXYPadProperties::slotAddClicked()
×
324
{
325
    /* Put all fixtures already present into a list of fixtures that
326
       will be disabled in the fixture selection dialog */
327
    QList <GroupHead> disabled;
×
328
    QTreeWidgetItemIterator twit(m_tree);
×
329
    while (*twit != NULL)
×
330
    {
331
        QVariant var((*twit)->data(KColumnFixture, Qt::UserRole));
×
332
        VCXYPadFixture fxi(m_doc, var);
×
333
        disabled << fxi.head();
×
334
        ++twit;
×
335
    }
×
336

337
    /* Disable all fixtures that don't have pan OR tilt channels */
338
    QListIterator <Fixture*> fxit(m_doc->fixtures());
×
339
    while (fxit.hasNext() == true)
×
340
    {
341
        Fixture* fixture(fxit.next());
×
342
        Q_ASSERT(fixture != NULL);
×
343

344
        // If a channel with pan or tilt group exists, don't disable this fixture
345
        if (fixture->channel(QLCChannel::Pan) == QLCChannel::invalid() &&
×
346
            fixture->channel(QLCChannel::Tilt) == QLCChannel::invalid())
×
347
        {
348
            // Disable all fixtures without pan or tilt channels
349
            disabled << fixture->id();
×
350
        }
351
        else
352
        {
353
            QVector <QLCFixtureHead> const& heads = fixture->fixtureMode()->heads();
×
354
            for (int i = 0; i < heads.size(); ++i)
×
355
            {
356
                if (heads[i].channelNumber(QLCChannel::Pan, QLCChannel::MSB) == QLCChannel::invalid() &&
×
357
                    heads[i].channelNumber(QLCChannel::Tilt, QLCChannel::MSB) == QLCChannel::invalid() &&
×
358
                    heads[i].channelNumber(QLCChannel::Pan, QLCChannel::LSB) == QLCChannel::invalid() &&
×
359
                    heads[i].channelNumber(QLCChannel::Tilt, QLCChannel::LSB) == QLCChannel::invalid())
×
360
                {
361
                    // Disable heads without pan or tilt channels
362
                    disabled << GroupHead(fixture->id(), i);
×
363
                }
364
            }
365
        }
366
    }
367

368
    /* Get a list of new fixtures to add to the pad */
369
    QTreeWidgetItem* item = NULL;
×
370
    FixtureSelection fs(this, m_doc);
×
371
    fs.setMultiSelection(true);
×
372
    fs.setSelectionMode(FixtureSelection::Heads);
×
373
    fs.setDisabledHeads(disabled);
×
374
    if (fs.exec() == QDialog::Accepted)
×
375
    {
376
        QListIterator <GroupHead> it(fs.selectedHeads());
×
377
        while (it.hasNext() == true)
×
378
        {
379
            VCXYPadFixture fxi(m_doc);
×
380
            fxi.setHead(it.next());
×
381
            item = new QTreeWidgetItem(m_tree);
×
382
            updateFixtureItem(item, fxi);
×
383
        }
×
384
    }
×
385

386
    if (item != NULL)
×
387
        m_tree->setCurrentItem(item);
×
388

389
    m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
390
}
×
391

392
void VCXYPadProperties::slotRemoveClicked()
×
393
{
394
    int r = QMessageBox::question(
×
395
                this, tr("Remove fixtures"),
×
396
                tr("Do you want to remove the selected fixtures?"),
×
397
                QMessageBox::Yes, QMessageBox::No);
398

399
    if (r == QMessageBox::Yes)
×
400
    {
401
        QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
402
        while (it.hasNext() == true)
×
403
            delete it.next();
×
404
    }
×
405
}
×
406

407
void VCXYPadProperties::slotEditClicked()
×
408
{
409
    /* Get a list of selected fixtures */
410
    QList <VCXYPadFixture> list(selectedFixtures());
×
411

412
    /* Start editor */
413
    VCXYPadFixtureEditor editor(this, list);
×
414
    if (editor.exec() == QDialog::Accepted)
×
415
    {
416
        QListIterator <VCXYPadFixture> it(editor.fixtures());
×
417
        while (it.hasNext() == true)
×
418
        {
419
            VCXYPadFixture fxi(it.next());
×
420
            QTreeWidgetItem* item = fixtureItem(fxi);
×
421

422
            updateFixtureItem(item, fxi);
×
423
        }
×
424
        m_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
425
    }
×
426
}
×
427

428
void VCXYPadProperties::slotSelectionChanged(QTreeWidgetItem* item)
×
429
{
430
    if (item == NULL)
×
431
    {
432
        m_removeButton->setEnabled(false);
×
433
        m_editButton->setEnabled(false);
×
434
    }
435
    else
436
    {
437
        m_removeButton->setEnabled(true);
×
438
        m_editButton->setEnabled(true);
×
439
    }
440
}
×
441

442
void VCXYPadProperties::slotPercentageRadioChecked()
×
443
{
444
    updateFixturesTree(VCXYPadFixture::Percentage);
×
445
}
×
446

447
void VCXYPadProperties::slotDegreesRadioChecked()
×
448
{
449
    updateFixturesTree(VCXYPadFixture::Degrees);
×
450
}
×
451

452
void VCXYPadProperties::slotDMXRadioChecked()
×
453
{
454
    updateFixturesTree(VCXYPadFixture::DMX);
×
455
}
×
456

457
/****************************************************************************
458
 * Input page
459
 ****************************************************************************/
460

461
void VCXYPadProperties::stopAutodetection(quint8 sourceId)
×
462
{
463
    if (sourceId != VCXYPad::panInputSourceId)
×
464
        m_panInputWidget->stopAutoDetection();
×
465
    if (sourceId != VCXYPad::panFineInputSourceId)
×
466
        m_panFineInputWidget->stopAutoDetection();
×
467
    if (sourceId != VCXYPad::tiltInputSourceId)
×
468
        m_tiltInputWidget->stopAutoDetection();
×
469
    if (sourceId != VCXYPad::tiltFineInputSourceId)
×
470
        m_tiltFineInputWidget->stopAutoDetection();
×
471
    if (sourceId != VCXYPad::widthInputSourceId)
×
472
        m_widthInputWidget->stopAutoDetection();
×
473
    if (sourceId != VCXYPad::heightInputSourceId)
×
474
        m_heightInputWidget->stopAutoDetection();
×
475
}
×
476

477
void VCXYPadProperties::slotPanAutoDetectToggled(bool toggled)
×
478
{
479
    if (toggled == true)
×
480
        stopAutodetection(VCXYPad::panInputSourceId);
×
481
}
×
482

483
void VCXYPadProperties::slotPanInputValueChanged(quint32 uni, quint32 ch)
×
484
{
485
    QSharedPointer<QLCInputSource> tmpSource = m_panInputWidget->inputSource();
×
486
    if (tmpSource->universe() != uni || tmpSource->channel() != ch)
×
487
        m_tiltInputWidget->setInputSource(
×
488
                    QSharedPointer<QLCInputSource>(new QLCInputSource(uni, ch)));
×
489
}
×
490

491
void VCXYPadProperties::slotPanFineAutoDetectToggled(bool toggled)
×
492
{
493
    if (toggled == true)
×
494
        stopAutodetection(VCXYPad::panFineInputSourceId);
×
495
}
×
496

497
void VCXYPadProperties::slotPanFineInputValueChanged(quint32 uni, quint32 ch)
×
498
{
499
    QSharedPointer<QLCInputSource> tmpSource = m_panFineInputWidget->inputSource();
×
500
    if (tmpSource->universe() != uni || tmpSource->channel() != ch)
×
501
        m_tiltFineInputWidget->setInputSource(
×
502
            QSharedPointer<QLCInputSource>(new QLCInputSource(uni, ch)));
×
503
}
×
504

505
void VCXYPadProperties::slotTiltAutoDetectToggled(bool toggled)
×
506
{
507
    if (toggled == true)
×
508
        stopAutodetection(VCXYPad::tiltInputSourceId);
×
509
}
×
510

511
void VCXYPadProperties::slotTiltInputValueChanged(quint32 uni, quint32 ch)
×
512
{
513
    QSharedPointer<QLCInputSource> tmpSource = m_tiltInputWidget->inputSource();
×
514
    if (tmpSource->universe() != uni || tmpSource->channel() != ch)
×
515
        m_panInputWidget->setInputSource(
×
516
                    QSharedPointer<QLCInputSource>(new QLCInputSource(uni, ch)));
×
517
}
×
518

519
void VCXYPadProperties::slotTiltFineAutoDetectToggled(bool toggled)
×
520
{
521
    if (toggled == true)
×
522
        stopAutodetection(VCXYPad::tiltFineInputSourceId);
×
523
}
×
524

525
void VCXYPadProperties::slotTiltFineInputValueChanged(quint32 uni, quint32 ch)
×
526
{
527
    QSharedPointer<QLCInputSource> tmpSource = m_tiltFineInputWidget->inputSource();
×
528
    if (tmpSource->universe() != uni || tmpSource->channel() != ch)
×
529
        m_panFineInputWidget->setInputSource(
×
530
            QSharedPointer<QLCInputSource>(new QLCInputSource(uni, ch)));
×
531
}
×
532

533
void VCXYPadProperties::writeDMX(MasterTimer *timer, QList<Universe *> universes)
×
534
{
535
    Q_UNUSED(timer);
536

537
    if (m_tab->currentIndex() != 2 || m_xyArea->hasPositionChanged() == false)
×
538
        return;
×
539

540
    //qDebug() << Q_FUNC_INFO;
541

542
    // This call also resets the m_changed flag in m_area
543
    QPointF pt = m_xyArea->position();
×
544

545
    /* Scale XY coordinate values to 0.0 - 1.0 */
546
    qreal x = SCALE(pt.x(), qreal(0), qreal(256), qreal(0), qreal(1));
×
547
    qreal y = SCALE(pt.y(), qreal(0), qreal(256), qreal(0), qreal(1));
×
548

549
    if (m_YInvertedRadio->isChecked())
×
550
        y = qreal(1) - y;
×
551

552
    QTreeWidgetItemIterator it(m_tree);
×
553
    while (*it != NULL)
×
554
    {
555
        QVariant var((*it)->data(KColumnFixture, Qt::UserRole));
×
556
        VCXYPadFixture fixture(m_doc, var);
×
557
        fixture.arm();
×
558
        quint32 universe = fixture.universe();
×
559
        if (universe == Universe::invalid())
×
560
            continue;
×
561

562
        QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
×
563
        if (fader.isNull())
×
564
        {
565
            fader = universes[universe]->requestFader();
×
566
            m_fadersMap[universe] = fader;
×
567
        }
568
        fixture.writeDMX(x, y, fader, universes[universe]);
×
569
        fixture.disarm();
×
570
        ++it;
×
571
    }
×
572
}
×
573

574
/********************************************************************
575
 * Presets
576
 ********************************************************************/
577

578
void VCXYPadProperties::updatePresetsTree()
×
579
{
580
    m_presetsTree->blockSignals(true);
×
581
    m_presetsTree->clear();
×
582

583
    for (int i = 0; i < m_presetList.count(); i++)
×
584
    {
585
        VCXYPadPreset *preset = m_presetList.at(i);
×
586
        QTreeWidgetItem *item = new QTreeWidgetItem(m_presetsTree);
×
587
        item->setData(0, Qt::UserRole, preset->m_id);
×
588
        item->setText(0, preset->m_name);
×
589
        if (preset->m_type == VCXYPadPreset::EFX)
×
590
            item->setIcon(0, QIcon(":/efx.png"));
×
591
        else if (preset->m_type == VCXYPadPreset::Scene)
×
592
            item->setIcon(0, QIcon(":/scene.png"));
×
593
        else if (preset->m_type == VCXYPadPreset::Position)
×
594
            item->setIcon(0, QIcon(":/xypad.png"));
×
595
        else if (preset->m_type == VCXYPadPreset::FixtureGroup)
×
596
            item->setIcon(0, QIcon(":/group.png"));
×
597
    }
598
    m_presetsTree->resizeColumnToContents(0);
×
599
    m_presetsTree->blockSignals(false);
×
600
}
×
601

602
void VCXYPadProperties::selectItemOnPresetsTree(quint8 presetId)
×
603
{
604
    m_presetsTree->blockSignals(true);
×
605

606
    for (int i = 0; i < m_presetsTree->topLevelItemCount(); ++i)
×
607
    {
608
        QTreeWidgetItem* treeItem = m_presetsTree->topLevelItem(i);
×
609
        if (treeItem->data(0, Qt::UserRole).toUInt() == presetId)
×
610
        {
611
            treeItem->setSelected(true);
×
612
            break;
×
613
        }
614
    }
615

616
    m_presetsTree->blockSignals(false);
×
617
}
×
618

619
void VCXYPadProperties::updateTreeItem(const VCXYPadPreset &preset)
×
620
{
621
    m_presetsTree->blockSignals(true);
×
622

623
    for (int i = 0; i < m_presetsTree->topLevelItemCount(); ++i)
×
624
    {
625
        QTreeWidgetItem* treeItem = m_presetsTree->topLevelItem(i);
×
626
        if (treeItem->data(0, Qt::UserRole).toUInt() == preset.m_id)
×
627
        {
628
            treeItem->setText(0, preset.m_name);
×
629
            m_presetsTree->resizeColumnToContents(0);
×
630
            m_presetsTree->blockSignals(false);
×
631
            return;
×
632
        }
633
    }
634
    Q_ASSERT(false);
×
635
}
636

637
VCXYPadPreset *VCXYPadProperties::getSelectedPreset()
×
638
{
639
    if (m_presetsTree->selectedItems().isEmpty())
×
640
        return NULL;
×
641

642
    QTreeWidgetItem* item = m_presetsTree->selectedItems().first();
×
643
    if (item != NULL)
×
644
    {
645
        quint8 presetID = item->data(0, Qt::UserRole).toUInt();
×
646
        foreach (VCXYPadPreset* preset, m_presetList)
×
647
        {
648
            if (preset->m_id == presetID)
×
649
                return preset;
×
650
        }
×
651
    }
652

653
    Q_ASSERT(false);
×
654
    return NULL;
655
}
656

657
void VCXYPadProperties::removePreset(quint8 id)
×
658
{
659
    for (int i = 0; i < m_presetList.count(); i++)
×
660
    {
661
        if (m_presetList.at(i)->m_id == id)
×
662
        {
663
            m_presetList.removeAt(i);
×
664
            return;
×
665
        }
666
    }
667
}
668

669
quint8 VCXYPadProperties::moveUpPreset(quint8 id)
×
670
{
671
    for (int i = 0; i < m_presetList.count(); i++)
×
672
    {
673
        if (m_presetList.at(i)->m_id == id)
×
674
        {
675
            if (i > 0)
×
676
            {
677
                //change order on hash preset structure.
678
                //presets are saved in hash and sort on id is used to create the preset list.
679
                //So swapping id change order every time that preset list is created (restore, dialog open, ...).
680
                quint8 dstPosID = m_presetList.at(i-1)->m_id;
×
681
                quint8 srcPosID = m_presetList.at(i)->m_id;
×
682

683
                m_presetList.at(i-1)->m_id = srcPosID;
×
684
                m_presetList.at(i)->m_id = dstPosID;
×
685

686
                //change order on current preset list...
687
                m_presetList.move(i, i-1);
×
688

689
                return dstPosID;
×
690
            }
691

692
            return id;
×
693
        }
694
    }
695

696
    return id;
×
697
}
698

699
quint8 VCXYPadProperties::moveDownPreset(quint8 id)
×
700
{
701
    for (int i = 0; i < m_presetList.count(); i++)
×
702
    {
703
        if (m_presetList.at(i)->m_id == id)
×
704
        {
705
            if (i < m_presetList.count() - 1)
×
706
            {
707
                //change order on hash preset structure.
708
                //presets are saved in hash and sort on id is used to create the preset list.
709
                //So swapping id change order every time that preset list is created (restore, dialog open, ...).
710
                quint8 dstPosID = m_presetList.at(i+1)->m_id;
×
711
                quint8 srcPosID = m_presetList.at(i)->m_id;
×
712

713
                m_presetList.at(i+1)->m_id = srcPosID;
×
714
                m_presetList.at(i)->m_id = dstPosID;
×
715

716
                //change order on current preset list...
717
                m_presetList.move(i, i+1);
×
718

719
                return dstPosID;
×
720
            }
721
            return id;
×
722
        }
723
    }
724

725
    return id;
×
726
}
727

728
void VCXYPadProperties::slotAddPositionClicked()
×
729
{
730
    VCXYPadPreset *newPreset = new VCXYPadPreset(++m_lastAssignedID);
×
731
    newPreset->m_type = VCXYPadPreset::Position;
×
732
    newPreset->m_dmxPos = m_xyArea->position();
×
733
    newPreset->m_name = QString("X:%1 - Y:%2").arg((int)newPreset->m_dmxPos.x()).arg((int)newPreset->m_dmxPos.y());
×
734
    m_presetList.append(newPreset);
×
735
    updatePresetsTree();
×
736
    selectItemOnPresetsTree(newPreset->m_id);
×
737
}
×
738

739
void VCXYPadProperties::slotAddEFXClicked()
×
740
{
741
    FunctionSelection fs(this, m_doc);
×
742
    fs.setMultiSelection(false);
×
743
    fs.setFilter(Function::EFXType, true);
×
744
    QList <quint32> ids;
×
745
    foreach (VCXYPadPreset *preset, m_presetList)
×
746
    {
747
        if (preset->m_type == VCXYPadPreset::EFX)
×
748
            ids.append(preset->m_funcID);
×
749
    }
×
750

751
    if (fs.exec() == QDialog::Accepted && fs.selection().size() > 0)
×
752
    {
753
        quint32 fID = fs.selection().first();
×
754
        Function *f = m_doc->function(fID);
×
755
        if (f == NULL || f->type() != Function::EFXType)
×
756
            return;
×
757
        VCXYPadPreset *newPreset = new VCXYPadPreset(++m_lastAssignedID);
×
758
        newPreset->m_type = VCXYPadPreset::EFX;
×
759
        newPreset->m_funcID = fID;
×
760
        newPreset->m_name = f->name();
×
761
        m_presetList.append(newPreset);
×
762
        updatePresetsTree();
×
763
        selectItemOnPresetsTree(newPreset->m_id);
×
764
    }
765
}
×
766

767
void VCXYPadProperties::slotAddSceneClicked()
×
768
{
769
    FunctionSelection fs(this, m_doc);
×
770
    fs.setMultiSelection(false);
×
771
    fs.setFilter(Function::SceneType, true);
×
772
    QList <quint32> ids;
×
773
    foreach (VCXYPadPreset *preset, m_presetList)
×
774
    {
775
        if (preset->m_type == VCXYPadPreset::Scene)
×
776
            ids.append(preset->m_funcID);
×
777
    }
×
778

779
    if (fs.exec() == QDialog::Accepted && fs.selection().size() > 0)
×
780
    {
781
        quint32 fID = fs.selection().first();
×
782
        Function *f = m_doc->function(fID);
×
783
        if (f == NULL || f->type() != Function::SceneType)
×
784
            return;
×
785
        Scene *scene = qobject_cast<Scene*>(f);
×
786
        bool panTiltFound = false;
×
787
        foreach (SceneValue scv, scene->values())
×
788
        {
789
            Fixture *fixture = m_doc->fixture(scv.fxi);
×
790
            if (fixture == NULL)
×
791
                continue;
×
792
            const QLCChannel *ch = fixture->channel(scv.channel);
×
793
            if (ch == NULL)
×
794
                continue;
×
795
            if (ch->group() == QLCChannel::Pan || ch->group() == QLCChannel::Tilt)
×
796
            {
797
                panTiltFound = true;
×
798
                break;
×
799
            }
800
        }
×
801
        if (panTiltFound == false)
×
802
        {
803
            QMessageBox::critical(this, tr("Error"),
×
804
                                  tr("The selected Scene does not include any Pan or Tilt channel.\n"
×
805
                                     "Please select one with such channels."),
806
                                  QMessageBox::Close);
807
            return;
×
808
        }
809
        VCXYPadPreset *newPreset = new VCXYPadPreset(++m_lastAssignedID);
×
810
        newPreset->m_type = VCXYPadPreset::Scene;
×
811
        newPreset->m_funcID = fID;
×
812
        newPreset->m_name = f->name();
×
813
        m_presetList.append(newPreset);
×
814
        updatePresetsTree();
×
815
        selectItemOnPresetsTree(newPreset->m_id);
×
816
    }
817
}
×
818

819
void VCXYPadProperties::slotAddFixtureGroupClicked()
×
820
{
821
    QList <GroupHead> enabled;
×
822
    QList <GroupHead> disabled;
×
823

824
    QTreeWidgetItemIterator it(m_tree);
×
825
    while (*it != NULL)
×
826
    {
827
        QVariant var((*it)->data(KColumnFixture, Qt::UserRole));
×
828
        VCXYPadFixture fxi(m_doc, var);
×
829
        enabled << fxi.head();
×
830
        ++it;
×
831
    }
×
832

833
    foreach (Fixture *fx, m_doc->fixtures())
×
834
    {
835
        for (int i = 0; i < fx->heads(); i++)
×
836
        {
837
            GroupHead gh(fx->id(), i);
×
838
            if (enabled.contains(gh) == false)
×
839
                disabled << gh;
×
840
        }
×
841
    }
×
842

843
    FixtureSelection fs(this, m_doc);
×
844
    fs.setMultiSelection(true);
×
845
    fs.setSelectionMode(FixtureSelection::Heads);
×
846
    fs.setDisabledHeads(disabled);
×
847
    if (fs.exec() == QDialog::Accepted)
×
848
    {
849
        QList<GroupHead> selectedGH = fs.selectedHeads();
×
850
        if (selectedGH.isEmpty())
×
851
        {
852
            QMessageBox::critical(this, tr("Error"),
×
853
                                  tr("Please select at least one fixture or head to create this type of preset!"),
×
854
                                  QMessageBox::Close);
855
            return;
×
856
        }
857

858
        VCXYPadPreset *newPreset = new VCXYPadPreset(++m_lastAssignedID);
×
859
        newPreset->m_type = VCXYPadPreset::FixtureGroup;
×
860
        newPreset->m_name = tr("Fixture Group");
×
861
        newPreset->setFixtureGroup(selectedGH);
×
862
        m_presetList.append(newPreset);
×
863
        updatePresetsTree();
×
864
        selectItemOnPresetsTree(newPreset->m_id);
×
865
    }
×
866
}
×
867

868
void VCXYPadProperties::slotRemovePresetClicked()
×
869
{
870
    if (m_presetsTree->selectedItems().isEmpty())
×
871
        return;
×
872
    QTreeWidgetItem *selItem = m_presetsTree->selectedItems().first();
×
873
    quint8 ctlID = selItem->data(0, Qt::UserRole).toUInt();
×
874
    removePreset(ctlID);
×
875
    updatePresetsTree();
×
876
}
877

878
void VCXYPadProperties::slotMoveUpPresetClicked()
×
879
{
880
    if (m_presetsTree->selectedItems().isEmpty())
×
881
        return;
×
882
    QTreeWidgetItem *selItem = m_presetsTree->selectedItems().first();
×
883
    quint8 ctlID = selItem->data(0, Qt::UserRole).toUInt();
×
884
    quint8 newID = moveUpPreset(ctlID);
×
885
    updatePresetsTree();
×
886

887
    //select item on new position. User can make multiple move up/down without need to select item every time.
888
    selectItemOnPresetsTree(newID);
×
889
}
890

891
void VCXYPadProperties::slotMoveDownPresetClicked()
×
892
{
893
    if (m_presetsTree->selectedItems().isEmpty())
×
894
        return;
×
895
    QTreeWidgetItem *selItem = m_presetsTree->selectedItems().first();
×
896
    quint8 ctlID = selItem->data(0, Qt::UserRole).toUInt();
×
897
    quint8 newID =moveDownPreset(ctlID);
×
898
    updatePresetsTree();
×
899

900
    //select item on new position. User can make multiple move up/down without need to select item every time.
901
    selectItemOnPresetsTree(newID);
×
902
}
903

904
void VCXYPadProperties::slotPresetNameEdited(const QString &newName)
×
905
{
906
    VCXYPadPreset* preset = getSelectedPreset();
×
907

908
    if (preset != NULL)
×
909
    {
910
        preset->m_name = newName;
×
911

912
        updateTreeItem(*preset);
×
913
    }
914
}
×
915

916
void VCXYPadProperties::slotPresetSelectionChanged()
×
917
{
918
    VCXYPadPreset *preset = getSelectedPreset();
×
919

920
    if (preset != NULL)
×
921
    {
922
        m_presetNameEdit->setText(preset->m_name);
×
923
        m_presetInputWidget->setInputSource(preset->m_inputSource);
×
924
        m_presetInputWidget->setKeySequence(preset->m_keySequence.toString(QKeySequence::NativeText));
×
925
        if (preset->m_type == VCXYPadPreset::EFX)
×
926
        {
927
            Function *f = m_doc->function(preset->functionID());
×
928
            if (f == NULL || f->type() != Function::EFXType)
×
929
                return;
×
930
            EFX *efx = qobject_cast<EFX*>(f);
×
931
            QPolygonF polygon;
×
932
            efx->preview(polygon);
×
933

934
            QVector <QPolygonF> fixturePoints;
×
935
            efx->previewFixtures(fixturePoints);
×
936

937
            m_xyArea->enableEFXPreview(true);
×
938
            m_xyArea->setEnabled(false);
×
939
            m_xyArea->setEFXPolygons(polygon, fixturePoints);
×
940
            m_xyArea->setEFXInterval(efx->duration());
×
941
        }
×
942
        else if (preset->m_type == VCXYPadPreset::Position)
×
943
        {
944
            m_xyArea->enableEFXPreview(false);
×
945
            m_xyArea->setEnabled(true);
×
946
            m_xyArea->blockSignals(true);
×
947
            m_xyArea->setPosition(preset->m_dmxPos);
×
948
            m_xyArea->repaint();
×
949
            m_xyArea->blockSignals(false);
×
950
        }
951
        else if (preset->m_type == VCXYPadPreset::Scene)
×
952
        {
953
            m_xyArea->enableEFXPreview(false);
×
954
            m_xyArea->setEnabled(false);
×
955
        }
956
    }
957
}
958

959
void VCXYPadProperties::slotXYPadPositionChanged(const QPointF &pt)
×
960
{
961
    VCXYPadPreset *preset = getSelectedPreset();
×
962

963
    if (preset != NULL)
×
964
    {
965
        preset->m_dmxPos = pt;
×
966
        if (preset->m_type == VCXYPadPreset::Position &&
×
967
            preset->m_name.startsWith("X:"))
×
968
        {
969
            preset->m_name = QString("X:%1 - Y:%2").arg((int)pt.x()).arg((int)pt.y());
×
970
            m_presetNameEdit->blockSignals(true);
×
971
            m_presetNameEdit->setText(preset->m_name);
×
972
            m_presetNameEdit->blockSignals(false);
×
973
        }
974
        updateTreeItem(*preset);
×
975
    }
976
}
×
977

978
void VCXYPadProperties::slotInputValueChanged(quint32 universe, quint32 channel)
×
979
{
980
    Q_UNUSED(universe);
981
    Q_UNUSED(channel);
982

983
    VCXYPadPreset *preset = getSelectedPreset();
×
984

985
    if (preset != NULL)
×
986
        preset->m_inputSource = m_presetInputWidget->inputSource();
×
987
}
×
988

989
void VCXYPadProperties::slotKeySequenceChanged(QKeySequence key)
×
990
{
991
    VCXYPadPreset *preset = getSelectedPreset();
×
992

993
    if (preset != NULL)
×
994
        preset->m_keySequence = key;
×
995
}
×
996

997
/****************************************************************************
998
 * OK/Cancel
999
 ****************************************************************************/
1000

1001
void VCXYPadProperties::accept()
×
1002
{
1003
    m_xypad->clearFixtures();
×
1004
    m_xypad->setCaption(m_nameEdit->text());
×
1005
    m_xypad->setInputSource(m_panInputWidget->inputSource(), VCXYPad::panInputSourceId);
×
1006
    m_xypad->setInputSource(m_panFineInputWidget->inputSource(), VCXYPad::panFineInputSourceId);
×
1007
    m_xypad->setInputSource(m_tiltInputWidget->inputSource(), VCXYPad::tiltInputSourceId);
×
1008
    m_xypad->setInputSource(m_tiltFineInputWidget->inputSource(), VCXYPad::tiltFineInputSourceId);
×
1009
    m_xypad->setInputSource(m_widthInputWidget->inputSource(), VCXYPad::widthInputSourceId);
×
1010
    m_xypad->setInputSource(m_heightInputWidget->inputSource(), VCXYPad::heightInputSourceId);
×
1011
    if (m_YNormalRadio->isChecked())
×
1012
        m_xypad->setInvertedAppearance(false);
×
1013
    else
1014
        m_xypad->setInvertedAppearance(true);
×
1015

1016
    QTreeWidgetItemIterator it(m_tree);
×
1017
    while (*it != NULL)
×
1018
    {
1019
        QVariant var((*it)->data(KColumnFixture, Qt::UserRole));
×
1020
        m_xypad->appendFixture(VCXYPadFixture(m_doc, var));
×
1021
        ++it;
×
1022
    }
×
1023

1024
    /* Controls */
1025
    m_xypad->resetPresets();
×
1026
    for (int i = 0; i < m_presetList.count(); i++)
×
1027
        m_xypad->addPreset(*m_presetList.at(i));
×
1028

1029
    QDialog::accept();
×
1030
}
×
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