• 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

6.08
/ui/src/clickandgowidget.cpp
1
/*
2
  Q Light Controller Plus
3
  clickandgowidget.cpp
4

5
  Copyright (c) Massimo Callegari
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 <QApplication>
21
#include <QMouseEvent>
22
#include <QPainter>
23
#include <QScreen>
24
#include <qmath.h>
25
#include <QDebug>
26
#include <QImage>
27

28
#include "clickandgowidget.h"
29
#include "qlccapability.h"
30
#include "qlcmacros.h"
31
#include "gradient.h"
32

33
#define CELL_W  150
34
#define CELL_H  45
35
#define TITLE_H  18
36

37
ClickAndGoWidget::ClickAndGoWidget(QWidget *parent) :
1✔
38
    QWidget(parent)
1✔
39
{
40
    // This makes the application crash when a clickAndGoWidget
41
    // is created in a QDialog.
42
    //    setAttribute(Qt::WA_StaticContents);
43

44
    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1✔
45
    setMouseTracking(true);
1✔
46

47
    m_type = None;
1✔
48
    m_linearColor = false;
1✔
49
    m_width = 10;
1✔
50
    m_height = 10;
1✔
51
    m_cols = 0;
1✔
52
    m_rows = 0;
1✔
53
    m_cellWidth = CELL_W;
1✔
54
    m_hoverCellIdx = -1;
1✔
55
    m_cellBarXpos = 1;
1✔
56
    m_cellBarYpos = 1;
1✔
57
    m_cellBarWidth = 0;
1✔
58
    m_levelLowLimit = 0;
1✔
59
    m_levelHighLimit = 255;
1✔
60
}
1✔
61

62
void ClickAndGoWidget::setupGradient(QColor begin, QColor end)
×
63
{
64
    QLinearGradient linearGrad(QPointF(10,0), QPointF(266, 0));
×
65
    linearGrad.setColorAt(0, begin);
×
66
    linearGrad.setColorAt(1, end);
×
67

68
    // create image and fill it with gradient
69
    m_width = 276;
×
70
    m_height = 40;
×
71
    m_image = QImage(m_width, m_height, QImage::Format_RGB32);
×
72
    QPainter painter(&m_image);
×
73
    painter.fillRect(m_image.rect(), linearGrad);
×
74

75
    m_linearColor = true;
×
76
}
×
77

78
void ClickAndGoWidget::setupColorPicker()
×
79
{
80
    int cw = 15;
×
81

82
    m_width = 256 + 30;
×
83
    m_height = 256;
×
84
    m_image = QImage(m_width, m_height, QImage::Format_RGB32);
×
85
    QPainter painter(&m_image);
×
86

87
    // Draw 16 default color squares
88
    painter.fillRect(0, 0, cw, 32, QColor(Qt::white));
×
89
    painter.fillRect(cw, 0, cw, 32, QColor(Qt::black));
×
90
    painter.fillRect(0, 32, cw, 64, QColor(Qt::red));
×
91
    painter.fillRect(cw, 32, cw, 64, QColor(Qt::darkRed));
×
92
    painter.fillRect(0, 64, cw, 96, QColor(Qt::green));
×
93
    painter.fillRect(cw, 64, cw, 96, QColor(Qt::darkGreen));
×
94
    painter.fillRect(0, 96, cw, 128, QColor(Qt::blue));
×
95
    painter.fillRect(cw, 96, cw, 128, QColor(Qt::darkBlue));
×
96
    painter.fillRect(0, 128, cw, 160, QColor(Qt::cyan));
×
97
    painter.fillRect(cw, 128, cw, 160, QColor(Qt::darkCyan));
×
98
    painter.fillRect(0, 160, cw, 192, QColor(Qt::magenta));
×
99
    painter.fillRect(cw, 160, cw, 192, QColor(Qt::darkMagenta));
×
100
    painter.fillRect(0, 192, cw, 224, QColor(Qt::yellow));
×
101
    painter.fillRect(cw, 192, cw, 224, QColor(Qt::darkYellow));
×
102
    painter.fillRect(0, 224, cw, 256, QColor(Qt::gray));
×
103
    painter.fillRect(cw, 224, cw, 256, QColor(Qt::darkGray));
×
104

105
    painter.drawImage(cw * 2, 0, Gradient::getRGBGradient());
×
106
}
×
107

108
void ClickAndGoWidget::setType(int type, const QLCChannel *chan)
×
109
{
110
    m_linearColor = false;
×
111
    //qDebug() << Q_FUNC_INFO << "Type: " << type;
112
    if (type == None)
×
113
    {
114
        m_image = QImage();
×
115
    }
116
    else if (type == Red)
×
117
        setupGradient(Qt::black, Qt::red);
×
118
    else if (type == Green)
×
119
        setupGradient(Qt::black, Qt::green);
×
120
    else if (type == Blue)
×
121
        setupGradient(Qt::black, Qt::blue);
×
122
    else if (type == Cyan)
×
123
        setupGradient(Qt::white, Qt::cyan);
×
124
    else if (type == Magenta)
×
125
        setupGradient(Qt::white, Qt::magenta);
×
126
    else if (type == Yellow)
×
127
        setupGradient(Qt::white, Qt::yellow);
×
128
    else if (type == Amber)
×
129
        setupGradient(Qt::black, 0xFFFF7E00);
×
130
    else if (type == White)
×
131
        setupGradient(Qt::black, Qt::white);
×
132
    else if (type == UV)
×
133
        setupGradient(Qt::black, 0xFF9400D3);
×
134
    else if (type == Lime)
×
135
        setupGradient(Qt::black, 0xFFADFF2F);
×
136
    else if (type == Indigo)
×
137
        setupGradient(Qt::black, 0xFF4B0082);
×
138
    else if (type == RGB || type == CMY)
×
139
    {
140
        setupColorPicker();
×
141
    }
142
    else if (type == Preset)
×
143
    {
144
        createPresetList(chan);
×
145
        setupPresetPicker();
×
146
    }
147

148
    m_type = type;
×
149
}
×
150

151
void ClickAndGoWidget::setLevelLowLimit(int min)
×
152
{
153
    this->m_levelLowLimit = min;
×
154
}
×
155

156
void ClickAndGoWidget::setLevelHighLimit(int max)
×
157
{
158
    this->m_levelHighLimit = max;
×
159
}
×
160

161
int ClickAndGoWidget::getType()
×
162
{
163
    return m_type;
×
164
}
165

166
QString ClickAndGoWidget::clickAndGoTypeToString(ClickAndGoWidget::ClickAndGo type)
×
167
{
168
    switch (type)
×
169
    {
170
        default:
×
171
        case None: return "None"; break;
×
172
        case Red: return "Red"; break;
×
173
        case Green: return "Green"; break;
×
174
        case Blue: return "Blue"; break;
×
175
        case Cyan: return "Cyan"; break;
×
176
        case Magenta: return "Magenta"; break;
×
177
        case Yellow: return "Yellow"; break;
×
178
        case Amber: return "Amber"; break;
×
179
        case White: return "White"; break;
×
180
        case UV: return "UV"; break;
×
181
        case Lime: return "Lime"; break;
×
182
        case Indigo: return "Indigo"; break;
×
183
        case RGB: return "RGB"; break;
×
184
        case CMY: return "CMY"; break;
×
185
        case Preset: return "Preset"; break;
×
186
    }
187
}
188

189
ClickAndGoWidget::ClickAndGo ClickAndGoWidget::stringToClickAndGoType(QString str)
×
190
{
191
    if (str == "Red") return Red;
×
192
    else if (str == "Green") return Green;
×
193
    else if (str == "Blue") return Blue;
×
194
    else if (str == "Cyan") return Cyan;
×
195
    else if (str == "Magenta") return Magenta;
×
196
    else if (str == "Yellow") return Yellow;
×
197
    else if (str == "Amber") return Amber;
×
198
    else if (str == "White") return White;
×
199
    else if (str == "UV") return UV;
×
200
    else if (str == "Lime") return Lime;
×
201
    else if (str == "Indigo") return Indigo;
×
202
    else if (str == "RGB") return RGB;
×
203
    else if (str == "CMY") return CMY;
×
204
    else if (str == "Preset") return Preset;
×
205

206
    return None;
×
207
}
208

209
QColor ClickAndGoWidget::getColorAt(uchar pos)
×
210
{
211
    if (m_linearColor == true)
×
212
    {
213
        QRgb col = m_image.pixel(10 + pos, 10);
×
214
        return QColor(col);
×
215
    }
216
    return QColor(0,0,0);
×
217
}
218

219
QImage ClickAndGoWidget::getImageFromValue(uchar value)
×
220
{
221
    /** If the widget type is a Preset, return directly
222
     *  the pre-loaded resource */
223
    if (m_type == Preset)
×
224
    {
225
        foreach (PresetResource res, m_resources)
×
226
        {
227
            if (value >= res.m_resLowLimit && value <= res.m_resHighLimit)
×
228
                return res.m_thumbnail;
×
229
        }
×
230
    }
231

232
    QImage img(42, 42, QImage::Format_RGB32);
×
233
    if (m_type == None)
×
234
    {
235
        img.fill(Qt::black);
×
236
    }
237
    else if (m_linearColor == true)
×
238
    {
239
        QRgb col = m_image.pixel(10 + value, 10);
×
240
        img.fill(QColor(col).rgb());
×
241
    }
242

243
    return img;
×
244
}
×
245

246
void ClickAndGoWidget::createPresetList(const QLCChannel *chan)
×
247
{
248
    int i = 1;
×
249
    if (chan == NULL)
×
250
        return;
×
251

252
    m_title = chan->name();
×
253
    m_resources.clear();
×
254

255
    //qDebug() << Q_FUNC_INFO << "cap #" << chan->capabilities().size();
256

257
    foreach (QLCCapability* cap, chan->capabilities())
×
258
    {
259
        if (cap->presetType() == QLCCapability::Picture)
×
260
        {
261
            m_resources.append(PresetResource(cap->resource(0).toString(), cap->name(),
×
262
                                              cap->min(), cap->max()));
×
263
        }
264
        else if (cap->presetType() == QLCCapability::SingleColor)
×
265
        {
266
            QColor col1 = cap->resource(0).value<QColor>();
×
267
            m_resources.append(PresetResource(col1, QColor(), cap->name(), cap->min(), cap->max()));
×
268
        }
269
        else if (cap->presetType() == QLCCapability::DoubleColor)
×
270
        {
271
            QColor col1 = cap->resource(0).value<QColor>();
×
272
            QColor col2 = cap->resource(1).value<QColor>();
×
273
            m_resources.append(PresetResource(col1, col2, cap->name(), cap->min(), cap->max()));
×
274
        }
275
        else
276
        {
277
            m_resources.append(PresetResource(i, cap->name(), cap->min(), cap->max()));
×
278
        }
279
        i++;
×
280
    }
×
281
}
282

283
void ClickAndGoWidget::setupPresetPicker()
×
284
{
285
    if (m_resources.size() == 0)
×
286
        return;
×
287

288
    QScreen *scr = QGuiApplication::screens().first();
×
289
    QRect screen = scr->availableGeometry();
×
290

291
    m_cols = 2;
×
292
    m_rows = qCeil((qreal)m_resources.size() / 2);
×
293
    m_width = m_cellWidth * m_cols;
×
294
    m_height = CELL_H * m_rows + TITLE_H;
×
295

296
    // first check if the menu fits vertically
297
    if (m_height > screen.height())
×
298
    {
299
        m_rows = qFloor((qreal)screen.height() / CELL_H);
×
300
        m_cols = qCeil((qreal)m_resources.size() / m_rows);
×
301
        m_width = m_cellWidth * m_cols;
×
302
        m_height = CELL_H * m_rows + TITLE_H;
×
303
    }
304

305
    // then check if it has to be rescaled horizontally
306
    if (m_width > screen.width())
×
307
    {
308
        m_cellWidth = screen.width() / m_cols;
×
309
        m_width = m_cellWidth * m_cols;
×
310
    }
311

312
    int x = 0;
×
313
    int y = 0;
×
314
    m_image = QImage(m_width, m_height, QImage::Format_RGB32);
×
315
    QPainter painter(&m_image);
×
316
    QPalette p = palette();
×
317
    painter.setRenderHint(QPainter::Antialiasing);
×
318
    painter.fillRect(0, 0, m_width, m_height, p.color(QPalette::Window));
×
319

320
    // title
321
    painter.setPen(p.color(QPalette::Text));
×
322
    painter.drawText(x + 3, y, m_width - 3, TITLE_H, Qt::AlignVCenter | Qt::TextSingleLine, m_title);
×
323
    y += TITLE_H;
×
324

325
    for (int i = 0; i < m_resources.size(); i++)
×
326
    {
327
        PresetResource res = m_resources.at(i);
×
328
        if (res.m_resLowLimit > m_levelHighLimit || res.m_resHighLimit < m_levelLowLimit)
×
329
            continue;
×
330
        painter.setPen(p.color(QPalette::Text));
×
331
        painter.drawRect(x, y, m_cellWidth, CELL_H);
×
332
        painter.drawImage(x + 1, y + 4, res.m_thumbnail);
×
333
        painter.drawText(x + 43, y + 4, m_cellWidth - 42, CELL_H - 5, Qt::TextWordWrap|Qt::AlignVCenter, res.m_descr);
×
334
        if (i % m_cols == m_cols - 1)
×
335
        {
336
            y += CELL_H;
×
337
            x = 0;
×
338
        }
339
        else
340
            x += m_cellWidth;
×
341

342
    }
×
343
}
×
344

345
QSize ClickAndGoWidget::sizeHint() const
×
346
{
347
    return QSize(m_width, m_height);
×
348
}
349

350
void ClickAndGoWidget::mousePressEvent(QMouseEvent *event)
×
351
{
352
    if (m_linearColor == true)
×
353
    {
354
        if (event->pos().x() <= 10)
×
355
            emit levelChanged(0);
×
356
        else if (event->pos().x() > 10 && event->pos().x() < 256)
×
357
            emit levelChanged((uchar)(event->pos().x() - 10));
×
358
        else
359
            emit levelChanged(255);
×
360
    }
361
    else if (m_type == RGB || m_type == CMY)
×
362
    {
363
        emit colorChanged(m_image.pixel(event->pos().x(), event->pos().y()));
×
364
    }
365
    else if (m_type == Preset)
×
366
    {
367
        if (m_hoverCellIdx >= 0 && m_hoverCellIdx < m_resources.length())
×
368
        {
369
            PresetResource res = m_resources.at(m_hoverCellIdx);
×
370
            qDebug() << "Mouse press. cellW: " << m_cellBarWidth << "min: " << res.m_resLowLimit << "max:" << res.m_resHighLimit;
×
371

372
            float f = SCALE(float(m_cellBarWidth),
×
373
                        float(0),
374
                        float(m_cellWidth),
375
                        float(0), float(res.m_resHighLimit - res.m_resLowLimit));
376
            emit levelAndPresetChanged((uchar)f + res.m_resLowLimit, res.m_thumbnail);
×
377
        }
×
378
    }
379
    QWidget::mousePressEvent(event);
×
380
}
×
381

382
void ClickAndGoWidget::mouseMoveEvent(QMouseEvent *event)
×
383
{
384
    if (m_linearColor == true && event->buttons() == Qt::LeftButton)
×
385
    {
386
        if (event->pos().x() <= 10)
×
387
            emit levelChanged(0);
×
388
        else if (event->pos().x() > 10 && event->pos().x() < 256)
×
389
            emit levelChanged((uchar)(event->pos().x() - 10));
×
390
        else
391
            emit levelChanged(255);
×
392
    }
393
    else if ((m_type == RGB || m_type == CMY) && event->buttons() == Qt::LeftButton)
×
394
    {
395
        emit colorChanged(m_image.pixel(event->pos().x(), event->pos().y()));
×
396
    }
397
    else if (m_type == Preset)
×
398
    {
399
        // calculate the index of the resource where the cursor is
400
        int floorX = qFloor(event->pos().x() / m_cellWidth);
×
401
        int floorY = qFloor((event->pos().y() - TITLE_H) / CELL_H);
×
402
        int tmpCellIDx = (floorY * m_cols) + floorX;
×
403
        if (event->pos().y() < TITLE_H || tmpCellIDx < 0 || tmpCellIDx >= m_resources.length())
×
404
        {
405
            m_hoverCellIdx = -1;
×
406
            update();
×
407
            return;
×
408
        }
409
        m_cellBarXpos = floorX * m_cellWidth;
×
410
        m_cellBarYpos = floorY * CELL_H + TITLE_H;
×
411
        m_cellBarWidth = event->pos().x() - m_cellBarXpos;
×
412
        m_hoverCellIdx = tmpCellIDx;
×
413
        update();
×
414
        qDebug() << "Idx:" << m_hoverCellIdx << "X:" << m_cellBarXpos << "mX:" << event->pos().x();
×
415
    }
416
}
417

418
void ClickAndGoWidget::paintEvent(QPaintEvent *event)
×
419
{
420
    Q_UNUSED(event)
421

422
    QPainter painter(this);
×
423
    painter.drawImage(QPoint(0, 0), m_image);
×
424
    if (m_type == Preset && m_hoverCellIdx >= 0)
×
425
    {
426
        painter.setPen(Qt::NoPen);
×
427
        painter.setBrush(QBrush(QColor(76, 136, 255, 255)));
×
428
        painter.drawRect(m_cellBarXpos, m_cellBarYpos + 1, m_cellBarWidth, 3);
×
429
    }
430
}
×
431

432

433
ClickAndGoWidget::PresetResource::PresetResource(QString path, QString text, uchar min, uchar max)
×
434
{
435
    m_descr = text;
×
436
    m_resLowLimit = min;
×
437
    m_resHighLimit = max;
×
438
    QImage px(path);
×
439
    m_thumbnail = QImage(40, 40, QImage::Format_RGB32);
×
440
    m_thumbnail.fill(Qt::white);
×
441
    QPainter painter(&m_thumbnail);
×
442
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
×
443
    painter.drawImage(QRect(0,0,40,40), px);
×
444
    //qDebug() << "PATH: adding " << path << ", descr: " << text;
445
}
×
446

447
ClickAndGoWidget::PresetResource::PresetResource(QColor color1, QColor color2,
×
448
                                                 QString text, uchar min, uchar max)
×
449
{
450
    m_descr = text;
×
451
    m_resLowLimit = min;
×
452
    m_resHighLimit = max;
×
453
    m_thumbnail = QImage(40, 40, QImage::Format_RGB32);
×
454
    if (color2.isValid() == false)
×
455
        m_thumbnail.fill(color1.rgb());
×
456
    else
457
    {
458
        QPainter painter(&m_thumbnail);
×
459
        painter.fillRect(0, 0, 20, 40, color1);
×
460
        painter.fillRect(20, 0, 40, 40, color2);
×
461
    }
×
462
    //qDebug() << "COLOR: adding " << color1.name() << ", descr: " << text;
463
}
×
464

465
ClickAndGoWidget::PresetResource::PresetResource(int index, QString text, uchar min, uchar max)
×
466
{
467
    m_descr = text;
×
468
    m_resLowLimit = min;
×
469
    m_resHighLimit = max;
×
470
    m_thumbnail = QImage(40, 40, QImage::Format_RGB32);
×
471
    m_thumbnail.fill(Qt::white);
×
472
    QFont tfont = QApplication::font();
×
473
    tfont.setBold(true);
×
474
    tfont.setPixelSize(20);
×
475
    QPainter painter(&m_thumbnail);
×
476
    painter.setFont(tfont);
×
477
    painter.drawText(0, 0, 40, 40, Qt::AlignHCenter|Qt::AlignVCenter, QString("%1").arg(index));
×
478
    //qDebug() << "GENERIC: adding " << index << ", descr: " << text;
479
}
×
480

481

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