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

mcallegari / qlcplus / 9022369978

09 May 2024 07:16PM UTC coverage: 31.498% (-0.6%) from 32.068%
9022369978

push

github

mcallegari
coverage: exclude enttecwing from coverage

15000 of 47622 relevant lines covered (31.5%)

16841.64 hits per line

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

73.14
/ui/src/virtualconsole/vcwidget.cpp
1
/*
2
  Q Light Controller Plus
3
  vcwidget.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

21
#include <QStyleOptionFrame>
22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QApplication>
25
#include <QInputDialog>
26
#include <QColorDialog>
27
#include <QFileDialog>
28
#include <QFontDialog>
29
#include <QMessageBox>
30
#include <QMouseEvent>
31
#include <QMetaObject>
32
#include <QPainter>
33
#include <QPalette>
34
#include <QCursor>
35
#include <QPixmap>
36
#include <QDebug>
37
#include <QBrush>
38
#include <QPoint>
39
#include <QStyle>
40
#include <QSize>
41
#include <QMenu>
42
#include <QList>
43

44
#include "qlcinputsource.h"
45
#include "qlcfile.h"
46

47
#include "qlcinputchannel.h"
48
#include "virtualconsole.h"
49
#include "inputpatch.h"
50
#include "vcwidget.h"
51
#include "doc.h"
52

53
#define GRID_RESOLUTION 5
54

55
VCWidget::VCWidget(QWidget* parent, Doc* doc)
177✔
56
    : QWidget(parent)
57
    , m_doc(doc)
58
    , m_id(invalidId())
354✔
59
    , m_disableState(false)
60
    , m_page(0)
61
    , m_allowChildren(false)
62
    , m_allowResize(true)
63
    , m_intensityOverrideId(Function::invalidAttributeId())
354✔
64
    , m_intensity(1.0)
65
    , m_liveEdit(VirtualConsole::instance()->liveEdit())
177✔
66
{
67
    Q_ASSERT(parent != NULL);
177✔
68
    Q_ASSERT(doc != NULL);
177✔
69

70
    /* Set the class name "VCWidget" as the object name as well */
71
    setObjectName(VCWidget::staticMetaObject.className());
177✔
72

73
    setMinimumSize(QSize(20, 20));
177✔
74

75
    m_type = UnknownWidget;
177✔
76
    m_hasCustomBackgroundColor = false;
177✔
77
    m_hasCustomForegroundColor = false;
177✔
78
    m_backgroundImage = QString();
177✔
79
    m_hasCustomFont = false;
177✔
80
    m_frameStyle = KVCFrameStyleNone;
177✔
81

82
    m_resizeMode = false;
177✔
83

84
    setBackgroundRole(QPalette::Window);
177✔
85
    setAutoFillBackground(true);
177✔
86
    setEnabled(true);
177✔
87

88
    connect(m_doc, SIGNAL(modeChanged(Doc::Mode)),
177✔
89
            this, SLOT(slotModeChanged(Doc::Mode)));
90

91
    /* Listen to the virtual console key signals */
92
    connect(VirtualConsole::instance(), SIGNAL(keyPressed(const QKeySequence&)),
177✔
93
            this, SLOT(slotKeyPressed(const QKeySequence&)));
94
    connect(VirtualConsole::instance(), SIGNAL(keyReleased(const QKeySequence&)),
177✔
95
            this, SLOT(slotKeyReleased(const QKeySequence&)));
96
}
177✔
97

98
VCWidget::~VCWidget()
177✔
99
{
100
}
177✔
101

102
/*****************************************************************************
103
 * ID
104
 *****************************************************************************/
105

106
void VCWidget::setID(quint32 id)
1✔
107
{
108
    /* Don't set doc modified status or emit changed signal, because this
109
       function is called only once during widget creation. */
110
    m_id = id;
1✔
111
}
1✔
112

113
quint32 VCWidget::id() const
18✔
114
{
115
    return m_id;
18✔
116
}
117

118
quint32 VCWidget::invalidId()
186✔
119
{
120
    return UINT_MAX;
186✔
121
}
122

123
/*********************************************************************
124
 * Type
125
 *********************************************************************/
126

127
void VCWidget::setType(int type)
153✔
128
{
129
    m_type = type;
153✔
130
}
153✔
131

132
int VCWidget::type()
5✔
133
{
134
    return m_type;
5✔
135
}
136

137
QString VCWidget::typeToString(int type)
×
138
{
139
    switch (type)
×
140
    {
141

142
        case ButtonWidget: return QString(tr("Button"));
×
143
        case SliderWidget: return QString(tr("Slider"));
×
144
        case XYPadWidget: return QString(tr("XYPad"));
×
145
        case FrameWidget: return QString(tr("Frame"));
×
146
        case SoloFrameWidget: return QString(tr("Solo frame"));
×
147
        case SpeedDialWidget: return QString(tr("Speed dial"));
×
148
        case CueListWidget: return QString(tr("Cue list"));
×
149
        case LabelWidget: return QString(tr("Label"));
×
150
        case AudioTriggersWidget: return QString(tr("Audio Triggers"));
×
151
        case AnimationWidget: return QString(tr("Animation"));
×
152
        case ClockWidget: return QString(tr("Clock"));
×
153
        case UnknownWidget:
×
154
        default:
155
             return QString(tr("Unknown"));
×
156
    }
157
    return QString(tr("Unknown"));
158
}
159

160
QIcon VCWidget::typeToIcon(int type)
×
161
{
162
    switch (type)
×
163
    {
164
        case ButtonWidget: return QIcon(":/button.png");
×
165
        case SliderWidget: return QIcon(":/slider.png");
×
166
        case XYPadWidget: return QIcon(":/xypad.png");
×
167
        case FrameWidget: return QIcon(":/frame.png");
×
168
        case SoloFrameWidget: return QIcon(":/soloframe.png");
×
169
        case SpeedDialWidget: return QIcon(":/speed.png");
×
170
        case CueListWidget: return QIcon(":/cuelist.png");
×
171
        case LabelWidget: return QIcon(":/label.png");
×
172
        case AudioTriggersWidget: return QIcon(":/audioinput.png");
×
173
        case AnimationWidget: return QIcon(":/rgbmatrix.png");
×
174
        case ClockWidget: return QIcon(":/clock.png");
×
175
        case UnknownWidget:
×
176
        default:
177
             return QIcon(":/virtualconsole.png");
×
178
    }
179
    return QIcon(":/virtualconsole.png");
180
}
181

182
/*********************************************************************
183
 * Disable state
184
 *********************************************************************/
185

186
void VCWidget::setDisableState(bool disable)
×
187
{
188
    m_disableState = disable;
×
189
    if (mode() == Doc::Operate)
×
190
    {
191
        setEnabled(!disable);
×
192
        enableWidgetUI(!disable);
×
193
    }
194

195
    emit disableStateChanged(m_disableState);
×
196
}
×
197

198
void VCWidget::enableWidgetUI(bool enable)
×
199
{
200
    Q_UNUSED(enable)
201
}
×
202

203
bool VCWidget::isDisabled()
76✔
204
{
205
    return m_disableState;
76✔
206
}
207

208
/*********************************************************************
209
 * Page
210
 *********************************************************************/
211

212
void VCWidget::setPage(int pNum)
×
213
{
214
    m_page = pNum;
×
215
}
×
216

217
int VCWidget::page()
46✔
218
{
219
    return m_page;
46✔
220
}
221

222
/*****************************************************************************
223
 * Clipboard
224
 *****************************************************************************/
225

226
bool VCWidget::copyFrom(const VCWidget* widget)
9✔
227
{
228
    if (widget == NULL)
9✔
229
        return false;
1✔
230

231
    setBackgroundImage(widget->m_backgroundImage);
8✔
232

233
    m_hasCustomBackgroundColor = widget->m_hasCustomBackgroundColor;
8✔
234
    if (m_hasCustomBackgroundColor == true)
8✔
235
        setBackgroundColor(widget->backgroundColor());
1✔
236

237
    m_hasCustomForegroundColor = widget->m_hasCustomForegroundColor;
8✔
238
    if (m_hasCustomForegroundColor == true)
8✔
239
        setForegroundColor(widget->foregroundColor());
1✔
240

241
    m_hasCustomFont = widget->m_hasCustomFont;
8✔
242
    if (m_hasCustomFont == true)
8✔
243
        setFont(widget->font());
1✔
244

245
    m_frameStyle = widget->m_frameStyle;
8✔
246

247
    setGeometry(widget->geometry());
8✔
248
    setCaption(widget->caption());
8✔
249

250
    m_allowChildren = widget->m_allowChildren;
8✔
251
    m_allowResize = widget->m_allowResize;
8✔
252

253
    QHashIterator <quint8, QSharedPointer<QLCInputSource> > it(widget->m_inputs);
8✔
254
    while (it.hasNext() == true)
11✔
255
    {
256
        it.next();
3✔
257
        quint8 id = it.key();
3✔
258
        QSharedPointer<QLCInputSource> src(new QLCInputSource(it.value()->universe(), it.value()->channel()));
6✔
259
        src->setFeedbackValue(QLCInputFeedback::LowerValue, it.value()->feedbackValue(QLCInputFeedback::LowerValue));
3✔
260
        src->setFeedbackValue(QLCInputFeedback::UpperValue, it.value()->feedbackValue(QLCInputFeedback::UpperValue));
3✔
261
        src->setFeedbackValue(QLCInputFeedback::MonitorValue, it.value()->feedbackValue(QLCInputFeedback::MonitorValue));
3✔
262
        src->setFeedbackExtraParams(QLCInputFeedback::LowerValue, it.value()->feedbackExtraParams(QLCInputFeedback::LowerValue));
3✔
263
        src->setFeedbackExtraParams(QLCInputFeedback::UpperValue, it.value()->feedbackExtraParams(QLCInputFeedback::UpperValue));
3✔
264
        src->setFeedbackExtraParams(QLCInputFeedback::MonitorValue, it.value()->feedbackExtraParams(QLCInputFeedback::MonitorValue));
3✔
265
        setInputSource(src, id);
3✔
266
    }
267

268
    m_page = widget->m_page;
8✔
269

270
    return true;
8✔
271
}
272

273
/*****************************************************************************
274
 * Background image
275
 *****************************************************************************/
276

277
void VCWidget::setBackgroundImage(const QString& path)
14✔
278
{
279
    QPalette pal = palette();
28✔
280

281
    m_hasCustomBackgroundColor = false;
14✔
282
    m_backgroundImage = path;
14✔
283

284
    pal.setBrush(QPalette::Window, QBrush(QPixmap(path)));
14✔
285
    setPalette(pal);
14✔
286

287
    m_doc->setModified();
14✔
288
}
14✔
289

290
QString VCWidget::backgroundImage() const
24✔
291
{
292
    return m_backgroundImage;
24✔
293
}
294

295

296
/*****************************************************************************
297
 * Background color
298
 *****************************************************************************/
299

300
void VCWidget::setBackgroundColor(const QColor& color)
11✔
301
{
302
    QPalette pal = palette();
22✔
303

304
    m_hasCustomBackgroundColor = true;
11✔
305
    m_backgroundImage = QString();
11✔
306

307
    pal.setColor(QPalette::Window, color);
11✔
308
    setPalette(pal);
11✔
309

310
    m_doc->setModified();
11✔
311
}
11✔
312

313
QColor VCWidget::backgroundColor() const
11✔
314
{
315
    return palette().color(QPalette::Window);
11✔
316
}
317

318
bool VCWidget::hasCustomBackgroundColor() const
29✔
319
{
320
    return m_hasCustomBackgroundColor;
29✔
321
}
322

323
void VCWidget::resetBackgroundColor()
3✔
324
{
325
    QColor fg;
3✔
326

327
    m_hasCustomBackgroundColor = false;
3✔
328
    m_backgroundImage = QString();
3✔
329

330
    /* Store foreground color */
331
    if (m_hasCustomForegroundColor == true)
3✔
332
        fg = palette().color(QPalette::WindowText);
2✔
333

334
    /* Reset the whole palette to application palette */
335
    setPalette(QApplication::palette());
3✔
336
    /* setAutoFillBackground(false); */
337

338
    /* Restore foreground color */
339
    if (fg.isValid() == true)
3✔
340
    {
341
        QPalette pal = palette();
4✔
342
        pal.setColor(QPalette::WindowText, fg);
2✔
343
        setPalette(pal);
2✔
344
    }
345

346
    m_doc->setModified();
3✔
347
}
3✔
348

349
/*****************************************************************************
350
 * Foreground color
351
 *****************************************************************************/
352

353
void VCWidget::setForegroundColor(const QColor& color)
7✔
354
{
355
    QPalette pal = palette();
14✔
356

357
    m_hasCustomForegroundColor = true;
7✔
358

359
    pal.setColor(QPalette::WindowText, color);
7✔
360
    setPalette(pal);
7✔
361

362
    m_doc->setModified();
7✔
363
}
7✔
364

365
QColor VCWidget::foregroundColor() const
10✔
366
{
367
    return palette().color(QPalette::WindowText);
10✔
368
}
369

370
bool VCWidget::hasCustomForegroundColor() const
21✔
371
{
372
    return m_hasCustomForegroundColor;
21✔
373
}
374

375
void VCWidget::resetForegroundColor()
4✔
376
{
377
    QColor bg;
4✔
378

379
    m_hasCustomForegroundColor = false;
4✔
380

381
    /* Store background color */
382
    if (hasCustomBackgroundColor() == true)
4✔
383
        bg = palette().color(QPalette::Window);
2✔
384

385
    /* Reset the whole palette to application palette */
386
    setPalette(QApplication::palette());
4✔
387

388
    /* Restore foreground color (the first two emit Doc::modified() signal) */
389
    if (bg.isValid() == true)
4✔
390
        setBackgroundColor(bg);
2✔
391
    else if (backgroundImage().isEmpty() == false)
2✔
392
        setBackgroundImage(backgroundImage());
1✔
393
    else
394
        m_doc->setModified();
1✔
395
}
4✔
396

397
/*****************************************************************************
398
 * Font
399
 *****************************************************************************/
400

401
void VCWidget::setFont(const QFont& font)
10✔
402
{
403
    m_hasCustomFont = true;
10✔
404
    QWidget::setFont(font);
10✔
405
    m_doc->setModified();
10✔
406
}
10✔
407

408
QFont VCWidget::font() const
25✔
409
{
410
    return QWidget::font();
25✔
411
}
412

413
bool VCWidget::hasCustomFont() const
12✔
414
{
415
    return m_hasCustomFont;
12✔
416
}
417

418
void VCWidget::resetFont()
1✔
419
{
420
    QWidget::setFont(QApplication::font());
1✔
421
    m_hasCustomFont = false;
1✔
422
    m_doc->setModified();
1✔
423
}
1✔
424

425
/*****************************************************************************
426
 * Caption
427
 *****************************************************************************/
428

429
void VCWidget::setCaption(const QString& text)
88✔
430
{
431
    setWindowTitle(text);
88✔
432
    update();
88✔
433
    m_doc->setModified();
88✔
434
}
88✔
435

436
QString VCWidget::caption() const
54✔
437
{
438
    return windowTitle();
54✔
439
}
440

441
/*****************************************************************************
442
 * Frame style
443
 *****************************************************************************/
444

445
void VCWidget::setFrameStyle(int style)
230✔
446
{
447
    m_frameStyle = style;
230✔
448
    update();
230✔
449
    m_doc->setModified();
230✔
450
}
230✔
451

452
int VCWidget::frameStyle() const
83✔
453
{
454
    return m_frameStyle;
83✔
455
}
456

457
void VCWidget::resetFrameStyle()
1✔
458
{
459
    setFrameStyle(KVCFrameStyleNone);
1✔
460
}
1✔
461

462
QString VCWidget::frameStyleToString(int style)
13✔
463
{
464
    if (style == KVCFrameStyleSunken)
13✔
465
        return "Sunken";
6✔
466
    else if (style == KVCFrameStyleRaised)
7✔
467
        return "Raised";
2✔
468
    else
469
        return "None";
5✔
470
}
471

472
int VCWidget::stringToFrameStyle(const QString& style)
6✔
473
{
474
    if (style == "Sunken")
6✔
475
        return KVCFrameStyleSunken;
3✔
476
    else if (style == "Raised")
3✔
477
        return KVCFrameStyleRaised;
1✔
478
    else
479
        return KVCFrameStyleNone;
2✔
480
}
481

482
/*****************************************************************************
483
 * Allow adding children
484
 *****************************************************************************/
485

486
void VCWidget::setAllowChildren(bool allow)
99✔
487
{
488
    m_allowChildren = allow;
99✔
489
}
99✔
490

491
bool VCWidget::allowChildren() const
17✔
492
{
493
    return m_allowChildren;
17✔
494
}
495

496
/*********************************************************************
497
 * Allow resizing
498
 *********************************************************************/
499

500
void VCWidget::setAllowResize(bool allow)
5✔
501
{
502
    m_allowResize = allow;
5✔
503
}
5✔
504

505
bool VCWidget::allowResize() const
8✔
506
{
507
    return m_allowResize;
8✔
508
}
509

510
/*****************************************************************************
511
 * Properties
512
 *****************************************************************************/
513

514
void VCWidget::editProperties()
×
515
{
516
    QMessageBox::information(this, staticMetaObject.className(),
×
517
                             tr("This widget has no properties"));
×
518
}
×
519

520
/*********************************************************************
521
 * Intensity
522
 *********************************************************************/
523

524
void VCWidget::adjustFunctionIntensity(Function *f, qreal value)
11✔
525
{
526
    if (f == NULL)
11✔
527
        return;
×
528

529
    //qDebug() << "adjustFunctionIntensity" << caption() << "value" << value;
530

531
    if (m_intensityOverrideId == Function::invalidAttributeId())
11✔
532
        m_intensityOverrideId = f->requestAttributeOverride(Function::Intensity, value);
11✔
533
    else
534
        f->adjustAttribute(value, m_intensityOverrideId);
×
535
}
536

537
void VCWidget::resetIntensityOverrideAttribute()
12✔
538
{
539
    m_intensityOverrideId = Function::invalidAttributeId();
12✔
540
}
12✔
541

542
void VCWidget::adjustIntensity(qreal val)
×
543
{
544
    m_intensity = val;
×
545
}
×
546

547
qreal VCWidget::intensity() const
31✔
548
{
549
    return m_intensity;
31✔
550
}
551

552
/*****************************************************************************
553
 * External input
554
 *****************************************************************************/
555

556
bool VCWidget::acceptsInput()
63✔
557
{
558
    if (mode() == Doc::Design || isEnabled() == false || isDisabled())
63✔
559
        return false;
7✔
560

561
    return true;
56✔
562
}
563

564
bool VCWidget::checkInputSource(quint32 universe, quint32 channel,
49✔
565
                                uchar value, QObject *sender, quint32 id)
566
{
567
    QSharedPointer<QLCInputSource> const& src = m_inputs.value(id);
98✔
568
    if (src.isNull())
49✔
569
        return false;
8✔
570

571
    if (src->isValid() && src->universe() == universe && src->channel() == channel)
41✔
572
    {
573
        // if the event has been fired by an external controller
574
        // and this channel is set to relative mode, inform the input source
575
        // and don't allow the event to pass through. A synthetic event
576
        // will be generated by the input source itself
577
        if (src != sender && src->needsUpdate())
22✔
578
        {
579
            src->updateInputValue(value);
×
580
            return false;
×
581
        }
582
        return true;
22✔
583
    }
584

585
    return false;
19✔
586
}
587

588
void VCWidget::setInputSource(QSharedPointer<QLCInputSource> const& source, quint8 id)
34✔
589
{
590
    // Connect when the first valid input source is set
591
    if (m_inputs.isEmpty() == true && !source.isNull() && source->isValid() == true)
34✔
592
    {
593
        connect(m_doc->inputOutputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
12✔
594
                this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
595
        connect(m_doc->inputOutputMap(), SIGNAL(profileChanged(quint32,QString)),
12✔
596
                this, SLOT(slotInputProfileChanged(quint32,QString)));
597
    }
598

599
    // Clear previous source
600
    if (m_inputs.contains(id))
34✔
601
    {
602
        disconnect(m_inputs.value(id).data(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
3✔
603
                this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
604
        m_inputs.remove(id);
3✔
605
    }
606

607
    // Assign
608
    if (!source.isNull() && source->isValid() == true)
34✔
609
    {
610
        m_inputs.insert(id, source);
30✔
611
        // now check if the source is defined in the associated universe
612
        // profile and if it has specific settings
613
        InputPatch *ip = m_doc->inputOutputMap()->inputPatch(source->universe());
30✔
614
        if (ip != NULL)
30✔
615
        {
616
            QLCInputProfile *profile = ip->profile();
×
617
            if (profile != NULL)
×
618
            {
619
                // Do not care about the page since input profiles don't do either
620
                QLCInputChannel *ich = profile->channel(source->channel() & 0xFFFF);
×
621
                if (ich != NULL)
×
622
                {
623
                    // retrieve plugin specific params for feedback
624
                    if (source->feedbackExtraParams(QLCInputFeedback::LowerValue).toInt() == -1)
×
625
                        source->setFeedbackExtraParams(QLCInputFeedback::LowerValue, profile->channelExtraParams(ich));
×
626
                    if (source->feedbackExtraParams(QLCInputFeedback::UpperValue).toInt() == -1 ||
×
627
                        !source->feedbackExtraParams(QLCInputFeedback::UpperValue).isValid())
×
628
                        source->setFeedbackExtraParams(QLCInputFeedback::UpperValue, profile->channelExtraParams(ich));
×
629
                    if (source->feedbackExtraParams(QLCInputFeedback::MonitorValue).toInt() == -1)
×
630
                        source->setFeedbackExtraParams(QLCInputFeedback::MonitorValue, profile->channelExtraParams(ich));
×
631

632
                    if (ich->movementType() == QLCInputChannel::Relative)
×
633
                    {
634
                        source->setWorkingMode(QLCInputSource::Relative);
×
635
                        source->setSensitivity(ich->movementSensitivity());
×
636
                        connect(source.data(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
×
637
                                this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
638
                    }
639
                    else if (ich->type() == QLCInputChannel::Encoder)
×
640
                    {
641
                        source->setWorkingMode(QLCInputSource::Encoder);
×
642
                        source->setSensitivity(ich->movementSensitivity());
×
643
                        connect(source.data(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
×
644
                                this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
645
                    }
646
                    else if (ich->type() == QLCInputChannel::Button)
×
647
                    {
648
                        if (ich->sendExtraPress() == true)
×
649
                        {
650
                            source->setSendExtraPressRelease(true);
×
651
                            connect(source.data(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
×
652
                                    this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
653
                        }
654

655
                        // user custom feedback have precedence over input profile custom feedback
656
                        uchar lower = source->feedbackValue(QLCInputFeedback::LowerValue) != 0 ?
×
657
                                      source->feedbackValue(QLCInputFeedback::LowerValue) :
×
658
                                      ich->lowerValue();
×
659
                        uchar upper = source->feedbackValue(QLCInputFeedback::UpperValue) != UCHAR_MAX ?
×
660
                                          source->feedbackValue(QLCInputFeedback::UpperValue) :
×
661
                                          ich->upperValue();
×
662

663
                        source->setFeedbackValue(QLCInputFeedback::LowerValue, lower);
×
664
                        source->setFeedbackValue(QLCInputFeedback::UpperValue, upper);
×
665
                    }
666
                }
667
            }
668
        }
669
    }
670

671
    // Disconnect when there are no more input sources present
672
    if (m_inputs.isEmpty() == true)
34✔
673
    {
674
        disconnect(m_doc->inputOutputMap(), SIGNAL(inputValueChanged(quint32,quint32,uchar)),
4✔
675
                   this, SLOT(slotInputValueChanged(quint32,quint32,uchar)));
676
        disconnect(m_doc->inputOutputMap(), SIGNAL(profileChanged(quint32,QString)),
4✔
677
                   this, SLOT(slotInputProfileChanged(quint32,QString)));
678
    }
679
}
34✔
680

681
QSharedPointer<QLCInputSource> VCWidget::inputSource(quint8 id) const
419✔
682
{
683
    return m_inputs.value(id);
419✔
684
}
685

686
void VCWidget::remapInputSources(int pgNum)
×
687
{
688
    foreach (quint8 s, m_inputs.keys())
×
689
    {
690
        QSharedPointer<QLCInputSource> src(m_inputs.value(s));
×
691
        src->setPage(pgNum);
×
692
        setInputSource(src, s);
×
693
    }
694
}
×
695

696
void VCWidget::sendFeedback(int value, quint8 id)
59✔
697
{
698
    /* Send input feedback */
699
    QSharedPointer<QLCInputSource> src = inputSource(id);
59✔
700
    sendFeedback(value, src);
59✔
701
}
59✔
702

703
void VCWidget::sendFeedback(int value, QSharedPointer<QLCInputSource> src, QVariant extraParams)
70✔
704
{
705
    if (src.isNull() || src->isValid() == false)
70✔
706
        return;
55✔
707

708
    // if in relative mode, send a "feedback" to this
709
    // input source so it can continue to emit values
710
    // from the right position
711
    if (src->needsUpdate())
15✔
712
        src->updateOuputValue(value);
×
713

714
    if (acceptsInput() == false)
15✔
715
        return;
3✔
716

717
    //qDebug() << "[VCWidget] Send feedback to uni" << src->universe() << "," << src->channel() << ", param" << extraParams;
718

719
    m_doc->inputOutputMap()->sendFeedBack(
24✔
720
        src->universe(), src->channel(), value,
721
        extraParams.isValid() ? extraParams : src->feedbackExtraParams(QLCInputFeedback::UpperValue));
24✔
722
}
723

724
void VCWidget::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
1✔
725
{
726
    Q_UNUSED(universe);
727
    Q_UNUSED(channel);
728
    Q_UNUSED(value);
729
}
1✔
730

731
void VCWidget::slotInputProfileChanged(quint32 universe, const QString &profileName)
×
732
{
733
    qDebug() << "[VCWdget] input profile changed" << profileName;
×
734

735
    QLCInputProfile *profile = m_doc->inputOutputMap()->profile(profileName);
×
736

737
    foreach (QSharedPointer<QLCInputSource> const& source, m_inputs.values())
×
738
    {
739
        if (!source.isNull() && source->universe() == universe)
×
740
        {
741
            // if the profile has been unset, reset all the valid
742
            // input sources to work in absolute mode
743
            if (profile == NULL)
×
744
            {
745
                source->setWorkingMode(QLCInputSource::Absolute);
×
746
            }
747
            else
748
            {
749
                QLCInputChannel *ich = profile->channel(source->channel());
×
750
                if (ich != NULL)
×
751
                {
752
                    if (ich->movementType() == QLCInputChannel::Absolute)
×
753
                        source->setWorkingMode(QLCInputSource::Absolute);
×
754
                    else
755
                    {
756
                        source->setWorkingMode(QLCInputSource::Relative);
×
757
                        source->setSensitivity(ich->movementSensitivity());
×
758
                    }
759
                }
760
            }
761
        }
762
    }
763
}
×
764

765
/*****************************************************************************
766
 * Key sequence handler
767
 *****************************************************************************/
768

769
QKeySequence VCWidget::stripKeySequence(const QKeySequence& seq)
12✔
770
{
771
    /* In QLC 3.2.x it is possible to set shortcuts like CTRL+X, but since
772
       CTRL is now the tap modifier, it must be stripped away. */
773
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
774
    int keys[4] = { 0, 0, 0, 0 };
775
    for (int i = 0; i < (int)seq.count() && i < 4; i++)
776
    {
777
        if ((seq[i] & Qt::ControlModifier) != 0)
778
            keys[i] = seq[i] & (~Qt::ControlModifier);
779
        else
780
            keys[i] = seq[i];
781
    }
782
#else
783
    QKeyCombination keys[4] = { Qt::Key_unknown, QKeyCombination::fromCombined(0), QKeyCombination::fromCombined(0), QKeyCombination::fromCombined(0)};
12✔
784
    for (int i = 0; i < (int)seq.count() && i < 4; i++)
24✔
785
    {
786
        if ((seq[i].toCombined() & Qt::ControlModifier) != 0)
12✔
787
            keys[i] = QKeyCombination::fromCombined(seq[i].toCombined() & (~Qt::ControlModifier));
4✔
788
        else
789
            keys[i] = seq[i];
8✔
790
    }
791
#endif
792
    return QKeySequence(keys[0], keys[1], keys[2], keys[3]);
24✔
793
}
794

795
void VCWidget::slotKeyPressed(const QKeySequence& keySequence)
1✔
796
{
797
    emit keyPressed(keySequence);
1✔
798
}
1✔
799

800
void VCWidget::slotKeyReleased(const QKeySequence& keySequence)
1✔
801
{
802
    emit keyReleased(keySequence);
1✔
803
}
1✔
804

805
/*****************************************************************************
806
 * Load & Save
807
 *****************************************************************************/
808

809
void VCWidget::postLoad()
6✔
810
{
811
    /* NOP */
812
}
6✔
813

814
bool VCWidget::loadXMLCommon(QXmlStreamReader &root)
14✔
815
{
816
    if (root.device() == NULL || root.hasError())
14✔
817
        return false;
×
818

819
    QXmlStreamAttributes attrs = root.attributes();
14✔
820

821
    /* ID */
822
    if (attrs.hasAttribute(KXMLQLCVCWidgetID))
14✔
823
        setID(attrs.value(KXMLQLCVCWidgetID).toString().toUInt());
×
824

825
    /* Caption */
826
    if (attrs.hasAttribute(KXMLQLCVCCaption))
14✔
827
        setCaption(attrs.value(KXMLQLCVCCaption).toString());
3✔
828

829
    /* Page */
830
    if (attrs.hasAttribute(KXMLQLCVCWidgetPage))
14✔
831
        setPage(attrs.value(KXMLQLCVCWidgetPage).toString().toInt());
×
832

833
    return true;
14✔
834
}
835

836
bool VCWidget::loadXMLAppearance(QXmlStreamReader &root)
9✔
837
{
838
    if (root.device() == NULL || root.hasError())
9✔
839
        return false;
×
840

841
    if (root.name() != KXMLQLCVCWidgetAppearance)
9✔
842
    {
843
        qWarning() << Q_FUNC_INFO << "Appearance node not found!";
1✔
844
        return false;
1✔
845
    }
846

847
    /* Children */
848
    while (root.readNextStartElement())
24✔
849
    {
850
        if (root.name() == KXMLQLCVCFrameStyle)
16✔
851
        {
852
            setFrameStyle(stringToFrameStyle(root.readElementText()));
2✔
853
        }
854
        else if (root.name() == KXMLQLCVCWidgetForegroundColor)
14✔
855
        {
856
            QString str = root.readElementText();
4✔
857
            if (str != KXMLQLCVCWidgetColorDefault)
2✔
858
                setForegroundColor(QColor(str.toUInt()));
1✔
859
            else if (hasCustomForegroundColor() == true)
1✔
860
                resetForegroundColor();
1✔
861
        }
862
        else if (root.name() == KXMLQLCVCWidgetBackgroundColor)
12✔
863
        {
864
            QString str = root.readElementText();
4✔
865
            if (str != KXMLQLCVCWidgetColorDefault)
2✔
866
                setBackgroundColor(QColor(str.toUInt()));
1✔
867
        }
868
        else if (root.name() == KXMLQLCVCWidgetBackgroundImage)
10✔
869
        {
870
            QString str = root.readElementText();
4✔
871
            if (str != KXMLQLCVCWidgetBackgroundImageNone)
2✔
872
                setBackgroundImage(m_doc->denormalizeComponentPath(str));
1✔
873
        }
874
        else if (root.name() == KXMLQLCVCWidgetFont)
8✔
875
        {
876
            QString str = root.readElementText();
12✔
877
            if (str != KXMLQLCVCWidgetFontDefault)
6✔
878
            {
879
                QFont font;
12✔
880
                font.fromString(str);
6✔
881
                setFont(font);
6✔
882
            }
883
        }
884
        else
885
        {
886
            qWarning() << Q_FUNC_INFO << "Unknown appearance tag:" << root.name();
2✔
887
            root.skipCurrentElement();
2✔
888
        }
889
    }
890

891
    return true;
8✔
892
}
893

894
QSharedPointer<QLCInputSource> VCWidget::getXMLInput(QXmlStreamReader &root)
7✔
895
{
896
    QXmlStreamAttributes attrs = root.attributes();
14✔
897

898
    quint32 uni = attrs.value(KXMLQLCVCWidgetInputUniverse).toString().toUInt();
7✔
899
    quint32 ch = attrs.value(KXMLQLCVCWidgetInputChannel).toString().toUInt();
7✔
900
    uchar min = 0, max = UCHAR_MAX, mon = UCHAR_MAX;
7✔
901

902
    QSharedPointer<QLCInputSource>newSrc = QSharedPointer<QLCInputSource>(new QLCInputSource(uni, ch));
7✔
903
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputLowerValue))
7✔
904
        min = uchar(attrs.value(KXMLQLCVCWidgetInputLowerValue).toString().toUInt());
×
905
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputUpperValue))
7✔
906
        max = uchar(attrs.value(KXMLQLCVCWidgetInputUpperValue).toString().toUInt());
×
907
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputMonitorValue))
7✔
908
        mon = uchar(attrs.value(KXMLQLCVCWidgetInputMonitorValue).toString().toUInt());
×
909

910
    newSrc->setFeedbackValue(QLCInputFeedback::LowerValue, min);
7✔
911
    newSrc->setFeedbackValue(QLCInputFeedback::UpperValue, max);
7✔
912
    newSrc->setFeedbackValue(QLCInputFeedback::MonitorValue, mon);
7✔
913

914
    // load feedback extra params
915
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputLowerParams))
7✔
916
        newSrc->setFeedbackExtraParams(QLCInputFeedback::LowerValue, attrs.value(KXMLQLCVCWidgetInputLowerParams).toInt());
×
917
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputUpperParams))
7✔
918
        newSrc->setFeedbackExtraParams(QLCInputFeedback::UpperValue, attrs.value(KXMLQLCVCWidgetInputUpperParams).toInt());
×
919
    if (attrs.hasAttribute(KXMLQLCVCWidgetInputMonitorParams))
7✔
920
        newSrc->setFeedbackExtraParams(QLCInputFeedback::MonitorValue, attrs.value(KXMLQLCVCWidgetInputMonitorParams).toInt());
×
921

922
    return newSrc;
14✔
923
}
924

925
bool VCWidget::loadXMLInput(QXmlStreamReader &root, const quint8 &id)
8✔
926
{
927
    if (root.device() == NULL || root.hasError())
8✔
928
        return false;
×
929

930
    if (root.name() != KXMLQLCVCWidgetInput)
8✔
931
        return false;
1✔
932

933
    QSharedPointer<QLCInputSource>newSrc = getXMLInput(root);
7✔
934

935
    setInputSource(newSrc, id);
7✔
936

937
    root.skipCurrentElement();
7✔
938

939
    return true;
7✔
940
}
941

942
QString VCWidget::loadXMLSources(QXmlStreamReader &root, quint8 sourceID)
6✔
943
{
944
    QString keyText;
6✔
945
    while (root.readNextStartElement())
14✔
946
    {
947
        if (root.name() == KXMLQLCVCWidgetInput)
8✔
948
        {
949
            loadXMLInput(root, sourceID);
4✔
950
        }
951
        else if (root.name() == KXMLQLCVCWidgetKey)
4✔
952
        {
953
            keyText = root.readElementText();
4✔
954
        }
955
        else
956
        {
957
            qWarning() << Q_FUNC_INFO << "Unknown source tag" << root.name().toString();
×
958
            root.skipCurrentElement();
×
959
        }
960
    }
961
    return keyText;
6✔
962
}
963

964
bool VCWidget::loadXMLInput(QXmlStreamReader &root, quint32* uni, quint32* ch) const
×
965
{
966
    if (root.name() != KXMLQLCVCWidgetInput)
×
967
    {
968
        qWarning() << Q_FUNC_INFO << "Input node not found!";
×
969
        return false;
×
970
    }
971
    else
972
    {
973
        QXmlStreamAttributes attrs = root.attributes();
×
974
        *uni = attrs.value(KXMLQLCVCWidgetInputUniverse).toString().toUInt();
×
975
        *ch = attrs.value(KXMLQLCVCWidgetInputChannel).toString().toUInt();
×
976
        root.skipCurrentElement();
×
977
    }
978

979
    return true;
×
980
}
981

982
QString VCWidget::extraParamToString(QVariant param)
30✔
983
{
984
    if (param.isValid() == false)
30✔
985
        return QString();
30✔
986

987
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
988
    if (param.type() == QVariant::Int && param.toInt() != -1)
989
        return QString::number(param.toInt());
990
#else
991
    if (param.metaType().id() == QMetaType::Int && param.toInt() != -1)
×
992
        return QString::number(param.toInt());
×
993
#endif
994
    return QString();
×
995
}
996

997
bool VCWidget::saveXMLCommon(QXmlStreamWriter *doc)
7✔
998
{
999
    Q_ASSERT(doc != NULL);
7✔
1000

1001
    /* Caption */
1002
    doc->writeAttribute(KXMLQLCVCCaption, caption());
7✔
1003

1004
    /* ID */
1005
    if (id() != VCWidget::invalidId())
7✔
1006
        doc->writeAttribute(KXMLQLCVCWidgetID, QString::number(id()));
×
1007

1008
    /* Page */
1009
    if (page() != 0)
7✔
1010
        doc->writeAttribute(KXMLQLCVCWidgetPage, QString::number(page()));
×
1011

1012
    return true;
7✔
1013
}
1014

1015
bool VCWidget::saveXMLAppearance(QXmlStreamWriter *doc)
9✔
1016
{
1017
    Q_ASSERT(doc != NULL);
9✔
1018

1019
    QString str;
×
1020

1021
    /* VC appearance entry */
1022
    doc->writeStartElement(KXMLQLCVCWidgetAppearance);
9✔
1023

1024
    /* Frame style */
1025
    doc->writeTextElement(KXMLQLCVCFrameStyle, frameStyleToString(frameStyle()));
9✔
1026

1027
    /* Foreground color */
1028
    if (hasCustomForegroundColor() == true)
9✔
1029
        str.setNum(foregroundColor().rgb());
1✔
1030
    else
1031
        str = KXMLQLCVCWidgetColorDefault;
8✔
1032
    doc->writeTextElement(KXMLQLCVCWidgetForegroundColor, str);
9✔
1033

1034
    /* Background color */
1035
    if (hasCustomBackgroundColor() == true)
9✔
1036
        str.setNum(backgroundColor().rgb());
1✔
1037
    else
1038
        str = KXMLQLCVCWidgetColorDefault;
8✔
1039
    doc->writeTextElement(KXMLQLCVCWidgetBackgroundColor, str);
9✔
1040

1041
    /* Background image */
1042
    if (backgroundImage().isEmpty() == false)
9✔
1043
        str = m_doc->normalizeComponentPath(m_backgroundImage);
1✔
1044
    else
1045
        str = KXMLQLCVCWidgetBackgroundImageNone;
8✔
1046
    doc->writeTextElement(KXMLQLCVCWidgetBackgroundImage, str);
9✔
1047

1048
    /* Font */
1049
    if (hasCustomFont() == true)
9✔
1050
        str = font().toString();
1✔
1051
    else
1052
        str = KXMLQLCVCWidgetFontDefault;
8✔
1053
    doc->writeTextElement(KXMLQLCVCWidgetFont, str);
9✔
1054

1055
    /* End the <Appearance> tag */
1056
    doc->writeEndElement();
9✔
1057

1058
    return true;
18✔
1059
}
1060

1061
bool VCWidget::saveXMLInput(QXmlStreamWriter *doc)
4✔
1062
{
1063
    return saveXMLInput(doc, inputSource());
4✔
1064
}
1065

1066
bool VCWidget::saveXMLInput(QXmlStreamWriter *doc,
12✔
1067
                            const QLCInputSource *src)
1068
{
1069
    Q_ASSERT(doc != NULL);
12✔
1070

1071
    if (src == NULL)
12✔
1072
        return false;
2✔
1073

1074
    if (src->isValid() == true)
10✔
1075
    {
1076
        doc->writeStartElement(KXMLQLCVCWidgetInput);
10✔
1077
        doc->writeAttribute(KXMLQLCVCWidgetInputUniverse, QString("%1").arg(src->universe()));
10✔
1078
        doc->writeAttribute(KXMLQLCVCWidgetInputChannel, QString("%1").arg(src->channel()));
10✔
1079
        if (src->feedbackValue(QLCInputFeedback::LowerValue) != 0)
10✔
1080
            doc->writeAttribute(KXMLQLCVCWidgetInputLowerValue, QString::number(src->feedbackValue(QLCInputFeedback::LowerValue)));
×
1081
        if (src->feedbackValue(QLCInputFeedback::UpperValue) != UCHAR_MAX)
10✔
1082
            doc->writeAttribute(KXMLQLCVCWidgetInputUpperValue, QString::number(src->feedbackValue(QLCInputFeedback::UpperValue)));
×
1083
        if (src->feedbackValue(QLCInputFeedback::MonitorValue) != UCHAR_MAX)
10✔
1084
            doc->writeAttribute(KXMLQLCVCWidgetInputMonitorValue, QString::number(src->feedbackValue(QLCInputFeedback::MonitorValue)));
×
1085

1086
        // save feedback extra params
1087
        QString extraParams = extraParamToString(src->feedbackExtraParams(QLCInputFeedback::LowerValue));
20✔
1088

1089
        if (!extraParams.isEmpty())
10✔
1090
            doc->writeAttribute(KXMLQLCVCWidgetInputLowerParams, extraParams);
×
1091

1092
        extraParams = extraParamToString(src->feedbackExtraParams(QLCInputFeedback::UpperValue));
10✔
1093

1094
        if (!extraParams.isEmpty())
10✔
1095
            doc->writeAttribute(KXMLQLCVCWidgetInputUpperParams, extraParams);
×
1096

1097
        extraParams = extraParamToString(src->feedbackExtraParams(QLCInputFeedback::MonitorValue));
10✔
1098

1099
        if (!extraParams.isEmpty())
10✔
1100
            doc->writeAttribute(KXMLQLCVCWidgetInputMonitorParams, extraParams);
×
1101

1102
        doc->writeEndElement();
10✔
1103
    }
1104

1105
    return true;
10✔
1106
}
1107

1108
bool VCWidget::saveXMLInput(QXmlStreamWriter *doc,
12✔
1109
                      QSharedPointer<QLCInputSource> const& src)
1110
{
1111
    return saveXMLInput(doc, src.data());
12✔
1112
}
1113

1114
bool VCWidget::saveXMLWindowState(QXmlStreamWriter *doc)
8✔
1115
{
1116
    Q_ASSERT(doc != NULL);
8✔
1117

1118
    /* Window state tag */
1119
    doc->writeStartElement(KXMLQLCWindowState);
8✔
1120

1121
    /* Visible status */
1122
    if (isVisible() == true)
8✔
1123
        doc->writeAttribute(KXMLQLCWindowStateVisible, KXMLQLCTrue);
2✔
1124
    else
1125
        doc->writeAttribute(KXMLQLCWindowStateVisible, KXMLQLCFalse);
6✔
1126

1127
    doc->writeAttribute(KXMLQLCWindowStateX, QString::number(x()));
8✔
1128
    doc->writeAttribute(KXMLQLCWindowStateY, QString::number(y()));
8✔
1129
    doc->writeAttribute(KXMLQLCWindowStateWidth, QString::number(width()));
8✔
1130
    doc->writeAttribute(KXMLQLCWindowStateHeight, QString::number(height()));
8✔
1131

1132
    doc->writeEndElement();
8✔
1133

1134
    return true;
8✔
1135
}
1136

1137
bool VCWidget::loadXMLWindowState(QXmlStreamReader &tag, int* x, int* y,
15✔
1138
                                  int* w, int* h, bool* visible)
1139
{
1140
    if (tag.device() == NULL || x == NULL || y == NULL || w == NULL || h == NULL ||
15✔
1141
            visible == NULL)
1142
        return false;
5✔
1143

1144
    if (tag.name() == KXMLQLCWindowState)
10✔
1145
    {
1146
        QXmlStreamAttributes attrs = tag.attributes();
9✔
1147
        *x = attrs.value(KXMLQLCWindowStateX).toString().toInt();
9✔
1148
        *y = attrs.value(KXMLQLCWindowStateY).toString().toInt();
9✔
1149
        *w = attrs.value(KXMLQLCWindowStateWidth).toString().toInt();
9✔
1150
        *h = attrs.value(KXMLQLCWindowStateHeight).toString().toInt();
9✔
1151

1152
        if (attrs.value(KXMLQLCWindowStateVisible).toString() == KXMLQLCTrue)
9✔
1153
            *visible = true;
8✔
1154
        else
1155
            *visible = false;
1✔
1156
        tag.skipCurrentElement();
9✔
1157

1158
        return true;
9✔
1159
    }
1160
    else
1161
    {
1162
        qWarning() << Q_FUNC_INFO << "Window state not found";
1✔
1163
        return false;
1✔
1164
    }
1165
}
1166

1167
/*****************************************************************************
1168
 * QLC+ Mode change
1169
 *****************************************************************************/
1170

1171
void VCWidget::setLiveEdit(bool liveEdit)
25✔
1172
{
1173
    if (m_doc->mode() == Doc::Design)
25✔
1174
        return;
25✔
1175

1176
    m_liveEdit = liveEdit;
×
1177

1178
    if (m_disableState)
×
1179
        setEnabled(m_liveEdit);
×
1180
    else
1181
        enableWidgetUI(!m_liveEdit);
×
1182

1183
    unsetCursor();
×
1184
    update();
×
1185
}
1186

1187
void VCWidget::cancelLiveEdit()
×
1188
{
1189
    m_liveEdit = false;
×
1190
}
×
1191

1192
void VCWidget::slotModeChanged(Doc::Mode mode)
66✔
1193
{
1194
    // make sure to exit from a 'deep' disable state
1195
    if (mode == Doc::Design)
66✔
1196
        setEnabled(true);
34✔
1197

1198
    /* Reset mouse cursor */
1199
    unsetCursor();
66✔
1200

1201
    /* Force an update to get rid of selection markers */
1202
    update();
66✔
1203
}
66✔
1204

1205
Doc::Mode VCWidget::mode() const
191✔
1206
{
1207
    Q_ASSERT(m_doc != NULL);
191✔
1208
    if (m_liveEdit)
191✔
1209
        return Doc::Design;
×
1210
    return m_doc->mode();
191✔
1211
}
1212

1213
/*****************************************************************************
1214
 * Widget menu
1215
 *****************************************************************************/
1216

1217
void VCWidget::invokeMenu(const QPoint& point)
×
1218
{
1219
    /* No point coming here if there is no VC instance */
1220
    VirtualConsole* vc = VirtualConsole::instance();
×
1221
    if (vc == NULL)
×
1222
        return;
×
1223

1224
    QMenu* menu = vc->editMenu();
×
1225
    Q_ASSERT(menu != NULL);
×
1226
    menu->exec(point);
×
1227
}
1228

1229
/*****************************************************************************
1230
 * Custom menu
1231
 *****************************************************************************/
1232

1233
QMenu* VCWidget::customMenu(QMenu* parentMenu)
3✔
1234
{
1235
    Q_UNUSED(parentMenu);
1236
    return NULL;
3✔
1237
}
1238

1239
/*****************************************************************************
1240
 * Widget move & resize
1241
 *****************************************************************************/
1242

1243
void VCWidget::resize(const QSize& size)
244✔
1244
{
1245
    QSize sz(size);
244✔
1246

1247
    // Force grid settings
1248
    sz.setWidth(size.width() - (size.width() % GRID_RESOLUTION));
244✔
1249
    sz.setHeight(size.height() - (size.height() % GRID_RESOLUTION));
244✔
1250

1251
    // Resize
1252
    QWidget::resize(sz);
244✔
1253
}
244✔
1254

1255
void VCWidget::move(const QPoint& point)
13✔
1256
{
1257
    QPoint pt(point);
13✔
1258

1259
    // Force grid settings
1260
    pt.setX(point.x() - (point.x() % GRID_RESOLUTION));
13✔
1261
    pt.setY(point.y() - (point.y() % GRID_RESOLUTION));
13✔
1262

1263
    // Don't move beyond left or right
1264
    if (pt.x() < 0)
13✔
1265
        pt.setX(0);
1✔
1266
    else if (pt.x() + rect().width() > parentWidget()->width())
12✔
1267
        pt.setX(parentWidget()->width() - rect().width());
1✔
1268

1269
    // Don't move beyond top or bottom
1270
    if (pt.y() < 0)
13✔
1271
        pt.setY(0);
1✔
1272
    else if (pt.y() + rect().height() > parentWidget()->height())
12✔
1273
        pt.setY(parentWidget()->height() - rect().height());
1✔
1274

1275
    // Move
1276
    QWidget::move(pt);
13✔
1277

1278
    m_doc->setModified();
13✔
1279
}
13✔
1280

1281
QPoint VCWidget::lastClickPoint() const
2✔
1282
{
1283
    return m_mousePressPoint;
2✔
1284
}
1285

1286
/*****************************************************************************
1287
 * Event handlers
1288
 *****************************************************************************/
1289

1290
void VCWidget::paintEvent(QPaintEvent* e)
32✔
1291
{
1292
    Q_UNUSED(e);
1293

1294
    /* No point coming here if there is no VC instance */
1295
    VirtualConsole* vc = VirtualConsole::instance();
32✔
1296
    if (vc == NULL)
32✔
1297
        return;
×
1298

1299
    QPainter painter(this);
64✔
1300

1301
    /* Draw frame according to style */
1302
    QStyleOptionFrame option;
64✔
1303
    option.initFrom(this);
32✔
1304

1305
    if (frameStyle() == KVCFrameStyleSunken)
32✔
1306
        option.state = QStyle::State_Sunken;
3✔
1307
    else if (frameStyle() == KVCFrameStyleRaised)
29✔
1308
        option.state = QStyle::State_Raised;
4✔
1309
    else
1310
        option.state = QStyle::State_None;
25✔
1311

1312
    if (mode() == Doc::Design)
32✔
1313
        option.state |= QStyle::State_Enabled;
28✔
1314

1315
    /* Draw a frame border if such is specified for this widget */
1316
    if (option.state != QStyle::State_None)
32✔
1317
        style()->drawPrimitive(QStyle::PE_Frame, &option, &painter, this);
29✔
1318

1319
    QWidget::paintEvent(e);
32✔
1320

1321
    /* Draw selection frame */
1322
    if (mode() == Doc::Design && vc->isWidgetSelected(this) == true)
32✔
1323
    {
1324
        /* Draw a dotted line around the widget */
1325
        QPen pen(Qt::DashLine);
8✔
1326
        pen.setColor(Qt::blue);
4✔
1327
        pen.setCapStyle(Qt::RoundCap);
4✔
1328
        pen.setWidth(0);
4✔
1329
        painter.setPen(pen);
4✔
1330
        painter.drawRect(0, 0, rect().width() - 1, rect().height() - 1);
4✔
1331

1332
        /* Draw a resize handle */
1333
        if (allowResize() == true)
4✔
1334
        {
1335
            QIcon icon(":/resize.png");
3✔
1336
            painter.drawPixmap(rect().width() - 16, rect().height() - 16,
3✔
1337
                               icon.pixmap(QSize(16, 16), QIcon::Normal, QIcon::On));
6✔
1338
        }
1339
    }
1340
}
1341

1342
void VCWidget::mousePressEvent(QMouseEvent* e)
2✔
1343
{
1344
    Q_ASSERT(e != NULL);
2✔
1345

1346
    if (mode() == Doc::Operate)
2✔
1347
    {
1348
        QWidget::mousePressEvent(e);
×
1349
        return;
×
1350
    }
1351

1352
    /* Perform widget de/selection in virtualconsole's selection buffer */
1353
    handleWidgetSelection(e);
2✔
1354

1355
    /* Resize mode */
1356
    if (m_resizeMode == true)
2✔
1357
    {
1358
        setMouseTracking(false);
×
1359
        m_resizeMode = false;
×
1360
    }
1361

1362
    /* Move, resize or context menu invocation */
1363
    if (e->button() & Qt::LeftButton || e->button() & Qt::MiddleButton)
2✔
1364
    {
1365
        /* Start moving or resizing based on where the click landed */
1366
        if (e->pos().x() > rect().width() - 10 && e->pos().y() > rect().height() - 10 && allowResize())
2✔
1367
        {
1368
            m_resizeMode = true;
×
1369
            setMouseTracking(true);
×
1370
            setCursor(QCursor(Qt::SizeFDiagCursor));
×
1371
        }
1372
        else
1373
        {
1374
            m_mousePressPoint = QPoint(e->pos().x(), e->pos().y());
2✔
1375
            setCursor(QCursor(Qt::SizeAllCursor));
2✔
1376
        }
1377
    }
1378
    else if (e->button() & Qt::RightButton)
×
1379
    {
1380
        /* Menu invocation */
1381
        m_mousePressPoint = QPoint(e->pos().x(), e->pos().y());
×
1382
        invokeMenu(mapToGlobal(e->pos()));
×
1383
    }
1384
}
1385

1386
void VCWidget::handleWidgetSelection(QMouseEvent* e)
3✔
1387
{
1388
    /* No point coming here if there is no VC */
1389
    VirtualConsole* vc = VirtualConsole::instance();
3✔
1390
    if (vc == NULL)
3✔
1391
        return;
×
1392

1393
    /* Widget selection logic (like in Qt Designer) */
1394
    if (e->button() == Qt::LeftButton)
3✔
1395
    {
1396
        if (e->modifiers() & Qt::ShiftModifier)
3✔
1397
        {
1398
            /* Toggle selection with LMB when shift is pressed */
1399
            bool selected = vc->isWidgetSelected(this);
×
1400
            vc->setWidgetSelected(this, !selected);
×
1401
        }
1402
        else
1403
        {
1404
            if (vc->isWidgetSelected(this) == false)
3✔
1405
            {
1406
                /* Select only this */
1407
                vc->clearWidgetSelection();
3✔
1408
                vc->setWidgetSelected(this, true);
3✔
1409
            }
1410
        }
1411
    }
1412
    else if (e->button() == Qt::RightButton)
×
1413
    {
1414
        if (vc->isWidgetSelected(this) == false)
×
1415
        {
1416
            /* Select only this */
1417
            vc->clearWidgetSelection();
×
1418
            vc->setWidgetSelected(this, true);
×
1419
        }
1420
    }
1421
}
1422

1423
void VCWidget::mouseReleaseEvent(QMouseEvent* e)
1✔
1424
{
1425
    if (mode() == Doc::Design)
1✔
1426
    {
1427
        unsetCursor();
1✔
1428
        m_resizeMode = false;
1✔
1429
        setMouseTracking(false);
1✔
1430
    }
1431
    else
1432
    {
1433
        QWidget::mouseReleaseEvent(e);
×
1434
    }
1435
}
1✔
1436

1437
void VCWidget::mouseDoubleClickEvent(QMouseEvent* e)
×
1438
{
1439
    if (mode() == Doc::Design)
×
1440
        editProperties();
×
1441
    else
1442
        QWidget::mouseDoubleClickEvent(e);
×
1443
}
×
1444

1445
void VCWidget::mouseMoveEvent(QMouseEvent* e)
2✔
1446
{
1447
    if (mode() == Doc::Design)
2✔
1448
    {
1449
        if (m_resizeMode == true)
2✔
1450
        {
1451
            QPoint p = mapToParent(e->pos());
×
1452
            resize(QSize(p.x() - x(), p.y() - y()));
×
1453
            m_doc->setModified();
×
1454
        }
1455
        else if (e->buttons() & Qt::LeftButton || e->buttons() & Qt::MiddleButton)
2✔
1456
        {
1457
            QPoint p = mapToParent(e->pos());
2✔
1458
            p.setX(p.x() - m_mousePressPoint.x());
2✔
1459
            p.setY(p.y() - m_mousePressPoint.y());
2✔
1460

1461
            move(p);
2✔
1462
            m_doc->setModified();
2✔
1463
        }
1464
    }
1465
    else
1466
    {
1467
        QWidget::mouseMoveEvent(e);
×
1468
    }
1469
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc