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

mcallegari / qlcplus / 8961243534

05 May 2024 09:23PM UTC coverage: 32.068% (+4.0%) from 28.094%
8961243534

push

github

mcallegari
Merge branch 'master' into qmltoqt6

902 of 2557 new or added lines in 140 files covered. (35.28%)

166 existing lines in 76 files now uncovered.

15395 of 48008 relevant lines covered (32.07%)

22949.67 hits per line

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

61.88
/ui/src/virtualconsole/vcxypadarea.cpp
1
/*
2
  Q Light Controller
3
  vcxypadarea.cpp
4

5
  Copyright (c) Heikki Junnila, Stefan Krumm
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 <QMouseEvent>
21
#include <QPainter>
22
#include <QPixmap>
23
#include <QCursor>
24
#include <qmath.h>
25
#include <QMutex>
26
#include <QDebug>
27
#include <QPoint>
28

29
#include "qlcmacros.h"
30

31
#include "efxpreviewarea.h"
32
#include "vcxypadarea.h"
33
#include "vcframe.h"
34

35
const qreal MAX_VALUE = 256.0;
36
const qreal MAX_DMX_VALUE = MAX_VALUE - 1.0/256;
37

38
/*****************************************************************************
39
 * Initialization
40
 *****************************************************************************/
41

42
VCXYPadArea::VCXYPadArea(QWidget* parent)
14✔
43
    : QFrame(parent)
44
    , m_changed(false)
45
    , m_activePixmap(":/xypad-point-blue.png")
46
    , m_fixturePixmap(":/xypad-point.png")
47
    , m_rangeDmxRect()
48
    , m_rangeWindowRect()
49
    , m_degreesRange()
50
    , m_previewArea(NULL)
14✔
51
{
52
    setFrameStyle(KVCFrameStyleSunken);
14✔
53
    setWindowTitle("XY Pad");
14✔
54
    setMode(Doc::Design);
14✔
55
    setFocusPolicy(Qt::ClickFocus);
14✔
56
    new QVBoxLayout(this);
14✔
57
}
14✔
58

59
VCXYPadArea::~VCXYPadArea()
23✔
60
{
61
}
23✔
62

63
void VCXYPadArea::setMode(Doc::Mode mode)
30✔
64
{
65
    m_mode = mode;
30✔
66
    if (mode == Doc::Design)
30✔
67
        setEnabled(false);
25✔
68
    else
69
        setEnabled(true);
5✔
70
    update();
30✔
71
}
30✔
72

73
/*****************************************************************************
74
 * Current XY position
75
 *****************************************************************************/
76

77
QPointF VCXYPadArea::position(bool resetChanged) const
33✔
78
{
79
    QMutexLocker locker(&m_mutex);
33✔
80
    QPointF pos(m_dmxPos);
33✔
81
    if (resetChanged)
33✔
82
        m_changed = false;
22✔
83
    return pos;
33✔
84
}
85

86
void VCXYPadArea::setPosition(const QPointF& point)
13✔
87
{
88
    {
89
        QMutexLocker locker(&m_mutex);
26✔
90

91
        if (m_dmxPos != point)
13✔
92
        {
93
            m_dmxPos = point;
12✔
94

95
            if (m_dmxPos.x() > MAX_DMX_VALUE)
12✔
96
                m_dmxPos.setX(MAX_DMX_VALUE);
2✔
97
            if (m_dmxPos.y() > MAX_DMX_VALUE)
12✔
98
                m_dmxPos.setY(MAX_DMX_VALUE);
2✔
99

100
            m_changed = true;
12✔
101
        }
102
    }
103

104
    emit positionChanged(point);
13✔
105
}
13✔
106

107
void VCXYPadArea::nudgePosition(qreal dx, qreal dy)
×
108
{
109
    {
110
        QMutexLocker locker(&m_mutex);
×
111

112
        m_dmxPos.setX(CLAMP(m_dmxPos.x() + dx, qreal(0), MAX_DMX_VALUE));
×
113
        m_dmxPos.setY(CLAMP(m_dmxPos.y() + dy, qreal(0), MAX_DMX_VALUE));
×
114

115
        m_changed = true;
×
116
    }
117

118
    emit positionChanged(m_dmxPos);
×
119
}
×
120

121
bool VCXYPadArea::hasPositionChanged()
6✔
122
{
123
    QMutexLocker locker(&m_mutex);
6✔
124
    return m_changed;
6✔
125
}
126

127
void VCXYPadArea::slotFixturePositions(const QVariantList positions)
×
128
{
129
    if (positions == m_fixturePositions)
×
130
        return;
×
131

132
    m_fixturePositions = positions;
×
133
    update();
×
134
}
135

136
void VCXYPadArea::checkDmxRange()
×
137
{
138
     QPointF pt(CLAMP(m_dmxPos.x(), m_rangeDmxRect.left(), m_rangeDmxRect.right()),
×
139
         CLAMP(m_dmxPos.y(), m_rangeDmxRect.top(), m_rangeDmxRect.bottom()));
×
140

141
     setPosition(pt);
×
142
}
×
143

144
void VCXYPadArea::updateWindowPos()
5✔
145
{
146
    m_windowPos.setX(SCALE(m_dmxPos.x(), qreal(0), qreal(256), qreal(0), qreal(width())));
5✔
147
    m_windowPos.setY(SCALE(m_dmxPos.y(), qreal(0), qreal(256), qreal(0), qreal(height())));
5✔
148
}
5✔
149

150
static int coarseByte(qreal value)
10✔
151
{
152
    return value;
10✔
153
}
154

155
static int fineByte(qreal value)
10✔
156
{
157
    return (value - floor(value)) * 256;
10✔
158
}
159

160
QString VCXYPadArea::positionString() const
5✔
161
{
162
    QPointF pos = position(false);
5✔
163
    return QString("%1.%2 : %3.%4")
10✔
164
        .arg(coarseByte(pos.x()), 3, 10, QChar('0'))
10✔
165
        .arg(fineByte(pos.x()), 3, 10, QChar('0'))
10✔
166
        .arg(coarseByte(pos.y()), 3, 10, QChar('0'))
10✔
167
        .arg(fineByte(pos.y()), 3,10, QChar('0'));
10✔
168
}
169

170
QString VCXYPadArea::angleString() const
5✔
171
{
172
    QPointF pos = position(false);
5✔
173
    QRectF range = degreesRange();
5✔
174

175
    if (range.isValid())
5✔
176
    {
177
        return QString("%1%2 : %3%4")
×
178
            .arg(range.x() + pos.x() * range.width() / 256)
×
179
            .arg(QChar(0xb0))
×
180
            .arg(range.y() + pos.y() * range.height() / 256)
×
181
            .arg(QChar(0xb0));
×
182
    }
183
    else
184
    {
185
        return QString("%1 % : %2 %")
10✔
186
            .arg(pos.x() * 100 / MAX_DMX_VALUE, 7, 'f', 3, '0')
10✔
187
            .arg(pos.y() * 100 / MAX_DMX_VALUE, 7, 'f', 3, '0');
5✔
188
    }
189

190
}
191

192
/*************************************************************************
193
 * Range window
194
 *************************************************************************/
195

196
QRectF VCXYPadArea::rangeWindow()
×
197
{
198
    return m_rangeDmxRect;
×
199
}
200

201
void VCXYPadArea::setRangeWindow(QRectF rect)
×
202
{
203
    m_rangeDmxRect = rect;
×
204
    updateRangeWindow();
×
205
}
×
206

207
void VCXYPadArea::updateRangeWindow()
5✔
208
{
209
    int x = m_rangeDmxRect.x() * width() / 256;
5✔
210
    int y = m_rangeDmxRect.y() * height() / 256;
5✔
211
    int w = m_rangeDmxRect.width() * width() / 256;
5✔
212
    int h = m_rangeDmxRect.height() * height() / 256;
5✔
213
    m_rangeWindowRect = QRect(x, y, w, h);
5✔
214
}
5✔
215

216
/*************************************************************************
217
 * Degrees range
218
 *************************************************************************/
219

220
QRectF VCXYPadArea::degreesRange() const
5✔
221
{
222
    return m_degreesRange;
5✔
223
}
224

225
void VCXYPadArea::setDegreesRange(QRectF range)
20✔
226
{
227
    m_degreesRange = range;
20✔
228
    update();
20✔
229
}
20✔
230

231
/*************************************************************************
232
 * EFX Preview
233
 *************************************************************************/
234

235
void VCXYPadArea::enableEFXPreview(bool enable)
×
236
{
237
    if (enable)
×
238
    {
239
        if (m_previewArea == NULL)
×
240
        {
241
            m_previewArea = new EFXPreviewArea(this);
×
242
            m_previewArea->setBackgroundAlpha(0);
×
243
            layout()->setContentsMargins(0, 0, 0, 0);
×
244
            layout()->addWidget(m_previewArea);
×
245
        }
246
    }
247
    else
248
    {
249
        if (m_previewArea)
×
250
        {
251
            m_previewArea->deleteLater();
×
252
            m_previewArea = NULL;
×
253
        }
254
    }
255
}
×
256

257
void VCXYPadArea::setEFXPolygons(const QPolygonF &pattern, const QVector<QPolygonF> fixtures)
×
258
{
259
    if (m_previewArea == NULL)
×
260
        enableEFXPreview(true);
×
261

262
    m_previewArea->setPolygon(pattern);
×
263
    m_previewArea->setFixturePolygons(fixtures);
×
264
}
×
265

266
void VCXYPadArea::setEFXInterval(uint duration)
×
267
{
268
    m_previewArea->draw(duration / m_previewArea->polygonsCount());
×
269
}
×
270

271
/*****************************************************************************
272
 * Event handlers
273
 *****************************************************************************/
274

275
void VCXYPadArea::paintEvent(QPaintEvent* e)
5✔
276
{
277
    if (m_rangeWindowRect.isValid() && (m_mode == Doc::Operate))
5✔
278
        checkDmxRange();
×
279

280
    /* Let the parent class draw its stuff first */
281
    QFrame::paintEvent(e);
5✔
282

283
    QPainter p(this);
10✔
284
    QPen pen;
10✔
285

286
    if (m_previewArea == NULL)
5✔
287
    {
288
        QString title = QString("%1%2%3\n%4\n")
5✔
289
            .arg(windowTitle())
10✔
290
            .arg(windowTitle().isEmpty() ? "" : "\n")
10✔
291
            .arg(positionString())
10✔
292
            .arg(angleString());
15✔
293

294
        /* Draw name (offset just a bit to avoid frame) */
295
        p.drawText(1, 1, width() - 2, height() - 2,
5✔
296
                   Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, title);
5✔
297

298
        QFont font = p.font();
5✔
299
        font.setPointSize(font.pointSize() - 2);
5✔
300
        p.setFont(font);
5✔
301
        p.drawText(1, 1, width() - 2, height() - 2,
5✔
302
                   Qt::AlignRight | Qt::AlignBottom | Qt::TextWordWrap, tr("Shift: fine, Ctrl:10x"));
10✔
303
    }
304
    /* Draw crosshairs to indicate the center position */
305
    pen.setStyle(Qt::DotLine);
5✔
306
    pen.setColor(palette().color(QPalette::WindowText));
5✔
307
    pen.setWidth(0);
5✔
308
    p.setPen(pen);
5✔
309
    p.drawLine(width() / 2, 0, width() / 2, height());
5✔
310
    p.drawLine(0, height() / 2, width(), height() / 2);
5✔
311

312
    /* Draw the range window if not full size */
313
    if (m_rangeWindowRect.isValid())
5✔
314
    {
315
        pen.setStyle(Qt::SolidLine);
×
316
        pen.setColor(QColor(0, 120, 0, 170));
×
317
        p.setPen(pen);
×
318
        p.fillRect(m_rangeWindowRect, QBrush(QColor(155, 200, 165, 130)));
×
319
        p.drawRect(m_rangeWindowRect);
×
320
    }
321

322
    updateWindowPos();
5✔
323

324
    if (m_previewArea == NULL)
5✔
325
    {
326
        foreach (QVariant pos, m_fixturePositions)
5✔
327
        {
328
            QPointF pt = pos.toPointF();
×
329
            pt.setX(SCALE(pt.x(), qreal(0), qreal(256), qreal(0), qreal(width())));
×
330
            pt.setY(SCALE(pt.y(), qreal(0), qreal(256), qreal(0), qreal(height())));
×
331

332
            p.drawPixmap(pt.x() - (m_fixturePixmap.width() / 2),
×
333
                     pt.y() - (m_fixturePixmap.height() / 2),
×
UNCOV
334
                     m_fixturePixmap);
×
335
        }
336

337
        /* Draw the current point pixmap */
338
        p.drawPixmap(m_windowPos.x() - (m_activePixmap.width() / 2),
5✔
339
                     m_windowPos.y() - (m_activePixmap.height() / 2),
5✔
340
                     m_activePixmap);
5✔
341
    }
342
}
5✔
343

344
void VCXYPadArea::resizeEvent(QResizeEvent *e)
5✔
345
{
346
    QFrame::resizeEvent(e);
5✔
347
    updateRangeWindow();
5✔
348
}
5✔
349

350
void VCXYPadArea::mousePressEvent(QMouseEvent* e)
2✔
351
{
352
    if (m_mode == Doc::Operate)
2✔
353
    {
354
        QPointF pt(CLAMP(e->pos().x(), 0, width()), CLAMP(e->pos().y(), 0, height()));
1✔
355
        pt.setX(SCALE(pt.x(), qreal(0), qreal(width()), qreal(0), qreal(256)));
1✔
356
        pt.setY(SCALE(pt.y(), qreal(0), qreal(height()), qreal(0), qreal(256)));
1✔
357

358
        setPosition(pt);
1✔
359
        setMouseTracking(true);
1✔
360
        setCursor(Qt::CrossCursor);
1✔
361
        update();
1✔
362
    }
363

364
    QFrame::mousePressEvent(e);
2✔
365
}
2✔
366

367
void VCXYPadArea::mouseReleaseEvent(QMouseEvent* e)
1✔
368
{
369
    if (m_mode == Doc::Operate)
1✔
370
    {
371
        QPointF pt(CLAMP(e->pos().x(), 0, width()), CLAMP(e->pos().y(), 0, height()));
1✔
372
        pt.setX(SCALE(pt.x(), qreal(0), qreal(width()), qreal(0), qreal(256)));
1✔
373
        pt.setY(SCALE(pt.y(), qreal(0), qreal(height()), qreal(0), qreal(256)));
1✔
374

375
        setPosition(pt);
1✔
376
        setMouseTracking(false);
1✔
377
        unsetCursor();
1✔
378
    }
379

380
    QFrame::mouseReleaseEvent(e);
1✔
381
}
1✔
382

383
void VCXYPadArea::mouseMoveEvent(QMouseEvent* e)
1✔
384
{
385
    if (m_mode == Doc::Operate)
1✔
386
    {
387
        QPointF pt(CLAMP(e->pos().x(), 0, width()), CLAMP(e->pos().y(), 0, height()));
1✔
388
        pt.setX(SCALE(pt.x(), qreal(0), qreal(width()), qreal(0), qreal(256)));
1✔
389
        pt.setY(SCALE(pt.y(), qreal(0), qreal(height()), qreal(0), qreal(256)));
1✔
390

391
        setPosition(pt);
1✔
392
        update();
1✔
393
    }
394

395
    QFrame::mouseMoveEvent(e);
1✔
396
}
1✔
397

398
void VCXYPadArea::keyPressEvent(QKeyEvent *e)
×
399
{
400
    if (m_mode == Doc::Operate)
×
401
    {
402
        qreal step = 1;
×
403
        if (e->modifiers().testFlag(Qt::ControlModifier))
×
404
            step *= 10;
×
405
        if (e->modifiers().testFlag(Qt::ShiftModifier))
×
406
            step /= 256;
×
407

408
        if (e->key() == Qt::Key_Left)
×
409
        {
410
            nudgePosition(-step , 0);
×
411
            update();
×
412
        }
413
        else if (e->key() == Qt::Key_Right)
×
414
        {
415
            nudgePosition(step, 0);
×
416
            update();
×
417
        }
418
        else if (e->key() == Qt::Key_Up)
×
419
        {
420
            nudgePosition(0, -step);
×
421
            update();
×
422
        }
423
        else if (e->key() == Qt::Key_Down)
×
424
        {
425
            nudgePosition(0, step);
×
426
            update();
×
427
        }
428
        else
429
        {
430
            QFrame::keyPressEvent(e);
×
431
        }
432
    }
433

434
    else QFrame::keyPressEvent(e);
×
435
}
×
436

437

438
void VCXYPadArea::keyReleaseEvent (QKeyEvent * e)
×
439
{
440
    QFrame::keyReleaseEvent(e);
×
441
}
×
442

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