• 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

98.48
/engine/src/rgbtext.cpp
1
/*
2
  Q Light Controller Plus
3
  rgbtext.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 <QXmlStreamReader>
22
#include <QXmlStreamWriter>
23
#include <QPainter>
24
#include <QImage>
25
#include <QDebug>
26

27
#include "rgbtext.h"
28

29
#define KXMLQLCRGBTextContent        QStringLiteral("Content")
30
#define KXMLQLCRGBTextFont           QStringLiteral("Font")
31
#define KXMLQLCRGBTextAnimationStyle QStringLiteral("Animation")
32
#define KXMLQLCRGBTextOffset         QStringLiteral("Offset")
33
#define KXMLQLCRGBTextOffsetX        QStringLiteral("X")
34
#define KXMLQLCRGBTextOffsetY        QStringLiteral("Y")
35

36
RGBText::RGBText(Doc * doc)
30✔
37
    : RGBAlgorithm(doc)
38
    , m_text(" Q LIGHT CONTROLLER + ")
30✔
39
    , m_animationStyle(Horizontal)
30✔
40
    , m_xOffset(0)
30✔
41
    , m_yOffset(0)
30✔
42
{
43
}
30✔
44

45
RGBText::RGBText(const RGBText& t)
4✔
46
    : RGBAlgorithm(t.doc())
47
    , m_text(t.text())
4✔
48
    , m_font(t.font())
4✔
49
    , m_animationStyle(t.animationStyle())
4✔
50
    , m_xOffset(t.xOffset())
4✔
51
    , m_yOffset(t.yOffset())
8✔
52
{
53
}
4✔
54

55
RGBText::~RGBText()
37✔
56
{
57
}
37✔
58

59
RGBAlgorithm* RGBText::clone() const
3✔
60
{
61
    RGBText* txt = new RGBText(*this);
3✔
62
    return static_cast<RGBAlgorithm*> (txt);
3✔
63
}
64

65
/****************************************************************************
66
 * Text & Font
67
 ****************************************************************************/
68

69
void RGBText::setText(const QString& str)
10✔
70
{
71
    m_text = str;
10✔
72
}
10✔
73

74
QString RGBText::text() const
9✔
75
{
76
    return m_text;
9✔
77
}
78

79
void RGBText::setFont(const QFont& font)
3✔
80
{
81
    m_font = font;
3✔
82
}
3✔
83

84
QFont RGBText::font() const
16✔
85
{
86
    return m_font;
16✔
87
}
88

89
/****************************************************************************
90
 * Animation
91
 ****************************************************************************/
92

93
void RGBText::setAnimationStyle(RGBText::AnimationStyle ani)
14✔
94
{
95
    if (ani >= StaticLetters && ani <= Vertical)
14✔
96
        m_animationStyle = ani;
12✔
97
    else
98
        m_animationStyle = StaticLetters;
2✔
99
}
14✔
100

101
RGBText::AnimationStyle RGBText::animationStyle() const
10,215✔
102
{
103
    return m_animationStyle;
10,215✔
104
}
105

106
QString RGBText::animationStyleToString(RGBText::AnimationStyle ani)
8✔
107
{
108
    switch (ani)
8✔
109
    {
110
    default:
3✔
111
    case StaticLetters:
112
        return QString("Letters");
3✔
113
    case Horizontal:
2✔
114
        return QString("Horizontal");
2✔
115
    case Vertical:
3✔
116
        return QString("Vertical");
3✔
117
    }
118
}
119

120
RGBText::AnimationStyle RGBText::stringToAnimationStyle(const QString& str)
8✔
121
{
122
    if (str == QString("Horizontal"))
8✔
123
        return Horizontal;
5✔
124
    else if (str == QString("Vertical"))
3✔
125
        return Vertical;
1✔
126
    else
127
        return StaticLetters;
2✔
128
}
129

130
QStringList RGBText::animationStyles()
1✔
131
{
132
    QStringList list;
1✔
133
    list << animationStyleToString(StaticLetters);
1✔
134
    list << animationStyleToString(Horizontal);
1✔
135
    list << animationStyleToString(Vertical);
1✔
136
    return list;
1✔
137
}
×
138

139
void RGBText::setXOffset(int offset)
6✔
140
{
141
    m_xOffset = offset;
6✔
142
}
6✔
143

144
int RGBText::xOffset() const
212✔
145
{
146
    return m_xOffset;
212✔
147
}
148

149
void RGBText::setYOffset(int offset)
6✔
150
{
151
    m_yOffset = offset;
6✔
152
}
6✔
153

154
int RGBText::yOffset() const
211✔
155
{
156
    return m_yOffset;
211✔
157
}
158

159
int RGBText::scrollingTextStepCount() const
100✔
160
{
161
    QFontMetrics fm(m_font);
100✔
162
    if (animationStyle() == Vertical)
100✔
163
        return m_text.length() * fm.ascent();
50✔
164
    else{
165
#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0))
166
        return fm.width(m_text);
167
#else
168
        return fm.horizontalAdvance(m_text);
50✔
169
#endif
170
    }
171
}
100✔
172

173
void RGBText::renderScrollingText(const QSize& size, uint rgb, int step, RGBMap &map) const
98✔
174
{
175
    QImage image;
98✔
176
    if (animationStyle() == Horizontal)
98✔
177
        image = QImage(scrollingTextStepCount(), size.height(), QImage::Format_RGB32);
49✔
178
    else
179
        image = QImage(size.width(), scrollingTextStepCount(), QImage::Format_RGB32);
49✔
180
    image.fill(QRgb(0));
98✔
181

182
    QPainter p(&image);
98✔
183
    p.setRenderHint(QPainter::TextAntialiasing, false);
98✔
184
    p.setRenderHint(QPainter::Antialiasing, false);
98✔
185
    p.setFont(m_font);
98✔
186
    p.setPen(QColor(rgb));
98✔
187

188
    if (animationStyle() == Vertical)
98✔
189
    {
190
        QFontMetrics fm(m_font);
49✔
191
        QRect rect(0, 0, image.width(), image.height());
49✔
192

193
        for (int i = 0; i < m_text.length(); i++)
196✔
194
        {
195
            rect.setY((i * fm.ascent()) + yOffset());
147✔
196
            rect.setX(xOffset());
147✔
197
            rect.setHeight(fm.ascent());
147✔
198
            p.drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, m_text.mid(i, 1));
147✔
199
        }
200
    }
49✔
201
    else
202
    {
203
        // Draw the whole text each time
204
        QRect rect(xOffset(), yOffset(), image.width(), image.height());
49✔
205
        p.drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, m_text);
49✔
206
    }
207
    p.end();
98✔
208

209
    // Treat the RGBMap as a "window" on top of the fully-drawn text and pick the
210
    // correct pixels according to $step.
211
    map.resize(size.height());
98✔
212
    for (int y = 0; y < size.height(); y++)
1,078✔
213
    {
214
        map[y].resize(size.width());
980✔
215
        for (int x = 0; x < size.width(); x++)
10,780✔
216
        {
217
            if (animationStyle() == Horizontal)
9,800✔
218
            {
219
                if (step + x < image.width())
4,900✔
220
                    map[y][x] = image.pixel(step + x, y);
4,350✔
221
            }
222
            else
223
            {
224
                if (step + y < image.height())
4,900✔
225
                    map[y][x] = image.pixel(x, step + y);
4,350✔
226
            }
227
        }
228
    }
229
}
98✔
230

231
void RGBText::renderStaticLetters(const QSize& size, uint rgb, int step, RGBMap &map) const
4✔
232
{
233
    QImage image(size, QImage::Format_RGB32);
4✔
234
    image.fill(QRgb(0));
4✔
235

236
    QPainter p(&image);
4✔
237
    p.setRenderHint(QPainter::TextAntialiasing, false);
4✔
238
    p.setRenderHint(QPainter::Antialiasing, false);
4✔
239
    p.setFont(m_font);
4✔
240
    p.setPen(QColor(rgb));
4✔
241

242
    // Draw one letter at a time
243
    QRect rect(xOffset(), yOffset(), size.width(), size.height());
4✔
244
    p.drawText(rect, Qt::AlignCenter, m_text.mid(step, 1));
4✔
245
    p.end();
4✔
246

247
    map.resize(size.height());
4✔
248
    for (int y = 0; y < size.height(); y++)
44✔
249
    {
250
        map[y].resize(size.width());
40✔
251
        for (int x = 0; x < size.width(); x++)
440✔
252
            map[y][x] = image.pixel(x, y);
400✔
253
    }
254
}
4✔
255

256
/****************************************************************************
257
 * RGBAlgorithm
258
 ****************************************************************************/
259

260
int RGBText::rgbMapStepCount(const QSize& size)
3✔
261
{
262
    Q_UNUSED(size);
263
    if (animationStyle() == StaticLetters)
3✔
264
        return m_text.length();
1✔
265
    else
266
        return scrollingTextStepCount();
2✔
267
}
268

269
void RGBText::rgbMapSetColors(const QVector<uint> &colors)
1✔
270
{
271
    Q_UNUSED(colors);
272
}
1✔
273

274
QVector<uint> RGBText::rgbMapGetColors()
1✔
275
{
276
    return QVector<uint>();
1✔
277
}
278

279
void RGBText::rgbMap(const QSize& size, uint rgb, int step, RGBMap &map)
102✔
280
{
281
    if (animationStyle() == StaticLetters)
102✔
282
        renderStaticLetters(size, rgb, step, map);
4✔
283
    else
284
        renderScrollingText(size, rgb, step, map);
98✔
285
}
102✔
286

287
QString RGBText::name() const
20✔
288
{
289
    return QString("Text");
20✔
290
}
291

292
QString RGBText::author() const
1✔
293
{
294
    return QString("Heikki Junnila");
1✔
295
}
296

297
int RGBText::apiVersion() const
1✔
298
{
299
    return 1;
1✔
300
}
301

302
RGBAlgorithm::Type RGBText::type() const
4✔
303
{
304
    return RGBAlgorithm::Text;
4✔
305
}
306

307
int RGBText::acceptColors() const
×
308
{
309
    return 2; // start and end colors accepted
×
310
}
311

312
bool RGBText::loadXML(QXmlStreamReader &root)
7✔
313
{
314
    if (root.name() != KXMLQLCRGBAlgorithm)
7✔
315
    {
316
        qWarning() << Q_FUNC_INFO << "RGB Algorithm node not found";
1✔
317
        return false;
1✔
318
    }
319

320
    if (root.attributes().value(KXMLQLCRGBAlgorithmType).toString() != KXMLQLCRGBText)
12✔
321
    {
322
        qWarning() << Q_FUNC_INFO << "RGB Algorithm is not Text";
1✔
323
        return false;
1✔
324
    }
325

326
    while (root.readNextStartElement())
25✔
327
    {
328
        if (root.name() == KXMLQLCRGBTextContent)
20✔
329
        {
330
            setText(root.readElementText());
4✔
331
        }
332
        else if (root.name() == KXMLQLCRGBTextFont)
16✔
333
        {
334
            QFont font;
4✔
335
            QString fontName = root.readElementText();
4✔
336
            if (font.fromString(fontName) == true)
4✔
337
                setFont(font);
1✔
338
            else
339
                qWarning() << Q_FUNC_INFO << "Invalid font:" << fontName;
3✔
340
        }
4✔
341
        else if (root.name() == KXMLQLCRGBTextAnimationStyle)
12✔
342
        {
343
            setAnimationStyle(stringToAnimationStyle(root.readElementText()));
4✔
344
        }
345
        else if (root.name() == KXMLQLCRGBTextOffset)
8✔
346
        {
347
            QString str;
4✔
348
            int value;
349
            bool ok;
350
            QXmlStreamAttributes attrs = root.attributes();
4✔
351

352
            str = attrs.value(KXMLQLCRGBTextOffsetX).toString();
4✔
353
            ok = false;
4✔
354
            value = str.toInt(&ok);
4✔
355
            if (ok == true)
4✔
356
                setXOffset(value);
3✔
357
            else
358
                qWarning() << Q_FUNC_INFO << "Invalid X offset:" << str;
1✔
359

360
            str = attrs.value(KXMLQLCRGBTextOffsetY).toString();
4✔
361
            ok = false;
4✔
362
            value = str.toInt(&ok);
4✔
363
            if (ok == true)
4✔
364
                setYOffset(value);
3✔
365
            else
366
                qWarning() << Q_FUNC_INFO << "Invalid Y offset:" << str;
1✔
367
            root.skipCurrentElement();
4✔
368
        }
4✔
369
        else
370
        {
371
            qWarning() << Q_FUNC_INFO << "Unknown RGBText tag:" << root.name();
4✔
372
            root.skipCurrentElement();
4✔
373
        }
374
    }
375

376
    return true;
5✔
377
}
378

379
bool RGBText::saveXML(QXmlStreamWriter *doc) const
1✔
380
{
381
    Q_ASSERT(doc != NULL);
1✔
382

383
    doc->writeStartElement(KXMLQLCRGBAlgorithm);
2✔
384
    doc->writeAttribute(KXMLQLCRGBAlgorithmType, KXMLQLCRGBText);
3✔
385

386
    doc->writeTextElement(KXMLQLCRGBTextContent, m_text);
2✔
387

388
    doc->writeTextElement(KXMLQLCRGBTextFont, m_font.toString());
2✔
389

390
    doc->writeTextElement(KXMLQLCRGBTextAnimationStyle, animationStyleToString(animationStyle()));
2✔
391

392
    doc->writeStartElement(KXMLQLCRGBTextOffset);
2✔
393
    doc->writeAttribute(KXMLQLCRGBTextOffsetX, QString::number(xOffset()));
2✔
394
    doc->writeAttribute(KXMLQLCRGBTextOffsetY, QString::number(yOffset()));
2✔
395
    doc->writeEndElement();
1✔
396

397
    /* End the <Algorithm> tag */
398
    doc->writeEndElement();
1✔
399

400
    return true;
1✔
401
}
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