Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Leander Schulten
Lichtsteuerung
Commits
34d477ab
Commit
34d477ab
authored
Aug 18, 2019
by
Leander Schulten
Browse files
Add virtual led consumer to provide a led visualization in the application. Closes
#32
parent
5a2cfdd3
Pipeline
#173147
passed with stage
in 1 minute and 48 seconds
Changes
12
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/Lichtsteuerung.pro
View file @
34d477ab
...
...
@@ -43,6 +43,7 @@ SOURCES += \
dmx/programm.cpp \
dmx/programmprototype.cpp \
modules/dmxconsumer.cpp \
modules/ledconsumer.cpp \
scanner.cpp \
test/testloopprogramm.cpp \
settings.cpp \
...
...
@@ -104,6 +105,7 @@ HEADERS += \
dmx/namedobject.h \
dmx/dmxchannelfilter.h \
modules/controlpoint.hpp \
modules/ledconsumer.h \
modules/scanner.hpp \
scanner.h \
updater.h \
...
...
src/main.cpp
View file @
34d477ab
...
...
@@ -48,6 +48,7 @@
#include "updater.h"
#include <QSslSocket>
#include "gui/controlitemdata.h"
#include "modules/ledconsumer.h"
#ifdef DrMinGW
#include "exchndl.h"
...
...
@@ -289,6 +290,7 @@ int main(int argc, char *argv[])
engine
.
rootContext
()
->
setContextProperty
(
"Settings"
,
&
settings
);
engine
.
rootContext
()
->
setContextProperty
(
"spotify"
,
&
spotify
);
engine
.
rootContext
()
->
setContextProperty
(
"updater"
,
&
updater
);
engine
.
rootContext
()
->
setContextProperty
(
"ledConsumer"
,
&
Modules
::
LedConsumer
::
allLedConsumer
);
QQmlEngine
::
setObjectOwnership
(
&
Driver
::
dmxValueModel
,
QQmlEngine
::
CppOwnership
);
engine
.
rootContext
()
->
setContextProperty
(
"dmxOutputValues"
,
&
Driver
::
dmxValueModel
);
engine
.
load
(
QUrl
(
QLatin1String
(
"qrc:/qml/main.qml"
)));
...
...
src/modelvector.h
View file @
34d477ab
...
...
@@ -246,11 +246,32 @@ public:
void
dataChanged
(
int
index_
){
emit
QAbstractItemModel
::
dataChanged
(
index
(
index_
),
index
(
index_
));
}
void
dataChanged
(
int
index_
,
int
length
){
emit
QAbstractItemModel
::
dataChanged
(
index
(
index_
),
index
(
index_
+
length
-
1
));
}
typename
std
::
vector
<
Type
>::
const_reference
operator
[](
int
index
)
const
{
return
model
[
index
];
}
void
resize
(
typename
std
::
vector
<
Type
>::
size_type
size
){
auto
diff
=
static_cast
<
int
>
(
size
)
-
ssize
();
if
(
diff
==
0
){
return
;
}
if
(
diff
>
0
)
{
beginPushBack
(
diff
);
}
else
{
beginRemoveRows
(
QModelIndex
(),
ssize
()
+
diff
,
ssize
()
-
1
);
}
model
.
resize
(
size
);
if
(
diff
>
0
)
{
endPushBack
();
}
else
{
endRemoveRows
();
}
}
void
clear
(){
if
(
size
()
==
0
){
return
;
...
...
src/modules/ledconsumer.cpp
0 → 100644
View file @
34d477ab
#include "ledconsumer.h"
namespace
Modules
{
LedConsumer
::
LedConsumer
()
:
Consumer
(
ValueType
::
RGB
),
name
(
"No Name"
){
allLedConsumer
.
push_back
(
this
);
name
.
setName
(
"Name"
);
name
.
setDescription
(
"A name to recognize this led strip in the led virtualisation view."
);
properties
.
push_back
(
&
name
);
using
namespace
std
::
chrono
;
startTimer
(
1s
);
}
void
LedConsumer
::
timerEvent
(
QTimerEvent
*
event
){
if
(
lastName
!=
name
.
getString
()){
emit
nameChanged
();
lastName
=
name
.
getString
();
}
}
void
LedConsumer
::
doStep
(
time_diff_t
diff
){
waitCounter
+=
diff
;
if
(
waitCounter
>=
15
){
waitCounter
=
0
;
// only update every 15 ms, the screen only has 60 fps
dataChanged
(
firstChangedIndex
,
changedLength
);
changedLength
=
0
;
firstChangedIndex
=
0
;
}
}
void
LedConsumer
::
setInputData
(
void
*
data
,
unsigned
int
index
,
unsigned
int
length
){
const
auto
maxIndex
=
std
::
min
(
index
+
length
,
static_cast
<
unsigned
int
>
(
size
()));
const
auto
maxLength
=
maxIndex
-
index
;
auto
*
rgbs
=
static_cast
<
rgb_t
*>
(
data
);
if
(
!
std
::
equal
(
rgbs
,
rgbs
+
maxLength
,
getVector
().
data
()
+
index
)){
std
::
copy
(
rgbs
,
rgbs
+
maxLength
,
getVector
().
data
()
+
index
);
if
(
changedLength
==
0
){
firstChangedIndex
=
static_cast
<
int
>
(
index
);
changedLength
=
static_cast
<
int
>
(
maxLength
);
}
else
if
(
changedLength
!=
static_cast
<
int
>
(
maxLength
)
||
firstChangedIndex
!=
static_cast
<
int
>
(
index
)){
// another range is changed, so simply mark the whole range as changed
const
auto
maxIndex
=
std
::
max
(
firstChangedIndex
+
changedLength
,
static_cast
<
int
>
(
index
)
+
static_cast
<
int
>
(
maxLength
));
firstChangedIndex
=
std
::
min
(
firstChangedIndex
,
static_cast
<
int
>
(
index
));
changedLength
=
maxIndex
-
firstChangedIndex
;
}
}
}
QHash
<
int
,
QByteArray
>
LedConsumer
::
roleNames
()
const
{
QHash
<
int
,
QByteArray
>
r
=
ModelVector
::
roleNames
();
r
[
RedDataRole
]
=
"r"
;
r
[
GreenDataRole
]
=
"g"
;
r
[
BlueDataRole
]
=
"b"
;
r
[
ColorDataRole
]
=
"ledColor"
;
return
r
;
}
QVariant
LedConsumer
::
data
(
const
QModelIndex
&
index
,
int
role
)
const
{
Q_UNUSED
(
role
);
if
(
index
.
row
()
>=
0
&&
index
.
row
()
<
int
(
size
())){
switch
(
role
)
{
case
RedDataRole
:
return
getVector
()[
index
.
row
()].
r
;
case
GreenDataRole
:
return
getVector
()[
index
.
row
()].
g
;
case
BlueDataRole
:
return
getVector
()[
index
.
row
()].
b
;
case
ColorDataRole
:
const
auto
&
rgb
=
getVector
()[
index
.
row
()];
return
QColor
(
rgb
.
r
,
rgb
.
g
,
rgb
.
b
);
}
}
return
QVariant
();
}
}
// namespace Modules
src/modules/ledconsumer.h
0 → 100644
View file @
34d477ab
#ifndef LEDCONSUMER_H
#define LEDCONSUMER_H
#include "consumer.hpp"
#include "modelvector.h"
#include <QColor>
#include <QObject>
#include <cmath>
namespace
Modules
{
class
LedConsumer
;
class
LedConsumer
:
public
ModelVector
<
rgb_t
>
,
public
Consumer
{
Q_OBJECT
Q_PROPERTY
(
bool
active
MEMBER
active
NOTIFY
activeChanged
)
Q_PROPERTY
(
QString
name
READ
getNameFromUser
NOTIFY
nameChanged
)
StringProperty
name
;
std
::
string
lastName
;
int
firstChangedIndex
=
0
;
int
changedLength
=
0
;
int
waitCounter
=
0
;
bool
active
=
false
;
protected:
void
timerEvent
(
QTimerEvent
*
event
);
public:
inline
static
ModelVector
<
LedConsumer
*>
allLedConsumer
;
LedConsumer
();
~
LedConsumer
()
override
{
allLedConsumer
.
removeAll
(
this
);
}
QString
getNameFromUser
()
const
{
return
QString
::
fromStdString
(
name
.
getString
());
}
void
setInputLength
(
unsigned
int
size
)
override
{
resize
(
size
);
}
unsigned
int
getInputLength
()
const
override
{
return
static_cast
<
unsigned
int
>
(
size
());
}
const
char
*
getName
()
const
override
{
return
"Virtual LED Consumer"
;
}
void
start
()
override
{
active
=
true
;
emit
activeChanged
();}
void
stop
()
override
{
active
=
false
;
emit
activeChanged
();}
void
show
()
override
{}
void
doStep
(
time_diff_t
diff
)
override
;
void
setInputData
(
void
*
data
,
unsigned
int
index
,
unsigned
int
length
)
override
;
enum
{
RedDataRole
=
Qt
::
UserRole
+
1
,
GreenDataRole
,
BlueDataRole
,
ColorDataRole
,
};
QHash
<
int
,
QByteArray
>
roleNames
()
const
override
;
QVariant
data
(
const
QModelIndex
&
index
,
int
role
)
const
override
;
signals:
void
activeChanged
();
void
nameChanged
();
};
}
// namespace Modules
Q_DECLARE_METATYPE
(
Modules
::
rgb_t
)
#endif // LEDCONSUMER_H
src/modules/modulemanager.cpp
View file @
34d477ab
...
...
@@ -9,6 +9,7 @@
#include "dmxconsumer.h"
#include "scanner.hpp"
#include "scanner.h"
#include "ledconsumer.h"
namespace
Modules
{
...
...
@@ -85,6 +86,10 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
consumer
.
emplace
(
"DMXConsumer"
,
"With the DMXConsumer class you can write to the DMX Channels"
,
-
1
,[](){
return
new
DMXConsumer
;
});
// add virtual led consumer to test
consumer
.
emplace
(
"Virtual LED Consumer"
,
"With this led consumer you can view the led stripes in the light control application"
,
-
1
,[](){
return
new
LedConsumer
;
});
}
void
ModuleManager
::
setSpotify
(
Spotify
::
Spotify
*
s
){
...
...
src/modules/types.h
View file @
34d477ab
...
...
@@ -41,6 +41,12 @@ namespace Modules {
this
->
b
*=
b
/
255.
f
;
return
*
this
;
}
bool
operator
==
(
rgb_t
other
)
const
{
return
r
==
other
.
r
&&
g
==
other
.
g
&&
b
==
other
.
b
;
}
bool
operator
!=
(
rgb_t
other
)
const
{
return
!
(
*
this
==
other
);
}
};
static_assert
(
sizeof
(
rgb_t
)
==
3
,
"size of rgb_t is not 3"
);
...
...
src/qml.qrc
View file @
34d477ab
...
...
@@ -76,5 +76,7 @@
<file>qml/HelpSystem/Help.qml</file>
<file>qml/HelpSystem/HelpButton.qml</file>
<file>qml/HelpSystem/HelpEntry.qml</file>
<file>qml/LedVisualisation/LedWindow.qml</file>
<file>qml/LedVisualisation/LedVisualisationView.qml</file>
</qresource>
</RCC>
src/qml/LedVisualisation/LedVisualisationView.qml
0 → 100644
View file @
34d477ab
import
QtQuick
2.12
import
QtQuick
.
Controls
2.12
import
QtQuick
.
Window
2.12
import
QtQuick
.
Layouts
1.12
ColumnLayout
{
property
bool
inOwnWindow
:
false
signal
moveToOwnWindow
;
Label
{
visible
:
!
inOwnWindow
Layout.margins
:
5
Layout.fillWidth
:
true
wrapMode
:
"
WordWrap
"
text
:
"
Here you can see a visualisation of the LED stripes used in the Program Block view. The refresh rate is 60 Hz, so the real stripe will look different with a refresh rate up to 1000 Hz.
"
}
ListView
{
Layout.margins
:
5
Layout.fillHeight
:
true
Layout.fillWidth
:
true
model
:
ledConsumer
implicitHeight
:
contentHeight
id
:
listView
clip
:
true
delegate
:
ColumnLayout
{
width
:
listView
.
width
Label
{
Layout.fillWidth
:
true
text
:
modelData
.
name
+
(
modelData
.
active
?
"
(running)
"
:
"
(not running)
"
);
}
Flow
{
Layout.fillWidth
:
true
Layout.bottomMargin
:
10
width
:
listView
.
width
Repeater
{
model
:
modelData
Rectangle
{
width
:
10
height
:
10
radius
:
5
color
:
ledColor
}
}
}
}
}
Button
{
visible
:
!
inOwnWindow
Layout.margins
:
5
text
:
"
Move into own window
"
onClicked
:
moveToOwnWindow
();
}
}
src/qml/LedVisualisation/LedWindow.qml
0 → 100644
View file @
34d477ab
import
QtQuick
2.12
import
QtQuick
.
Controls
2.12
import
QtQuick
.
Window
2.12
import
"
..
"
Window
{
property
VerticalTabButton
button
:
null
property
LedVisualisationView
view
:
null
flags
:
Qt
.
WindowStaysOnTopHint
|
Qt
.
Dialog
|
Qt
.
WindowCloseButtonHint
|
Qt
.
WindowTitleHint
title
:
"
Virtual LED Stripes
"
// TODO: reuse component from SwipeView (does not work on first try)
LedVisualisationView
{
id
:
root
anchors.fill
:
parent
inOwnWindow
:
true
}
}
src/qml/VerticalTabButton.qml
View file @
34d477ab
...
...
@@ -4,5 +4,5 @@ import QtQuick.Controls 2.4
TabButton
{
topPadding
:
6
bottomPadding
:
6
width
:
parent
.
width
width
:
parent
?
parent
.
width
:
100
}
src/qml/main.qml
View file @
34d477ab
import
QtQuick
2.
7
import
QtQuick
2.
12
import
QtQuick
.
Controls
2.12
import
QtQuick
.
Layouts
1.
0
import
QtQuick
.
Layouts
1.
12
import
custom
.
licht
1.0
import
"
ControlPane
"
import
"
components
"
import
"
HelpSystem
"
import
"
LedVisualisation
"
ApplicationWindow
{
visible
:
true
...
...
@@ -106,6 +107,9 @@ ApplicationWindow {
text
:
qsTr
(
"
Module
\n
Programs
"
)
enabled
:
UserManagment
.
currentUser
.
havePermission
(
Permission
.
MODULE_PROGRAMS_TAB
);
}
VerticalTabButton
{
text
:
qsTr
(
"
LED
\n
Visualisations
"
)
}
VerticalTabButton
{
text
:
qsTr
(
"
Graph
"
)
}
...
...
@@ -221,6 +225,10 @@ ApplicationWindow {
enabled
:
UserManagment
.
currentUser
.
havePermission
(
Permission
.
MODULE_PROGRAMS_TAB
);
}
LedVisualisationView
{
onMoveToOwnWindow
:
ledWindow
.
moveToWindow
(
SwipeView
.
index
);
}
FFTGraphView
{}
Oscillogram
{
...
...
@@ -230,6 +238,32 @@ ApplicationWindow {
}
}
LedWindow
{
id
:
ledWindow
property
int
insertAtIndex
function
moveToWindow
(
index
){
let
wasNeverVisible
=
x
===
0
;
const
globalPos
=
swipeView
.
itemAt
(
index
).
mapToGlobal
(
0
,
0
);
if
(
wasNeverVisible
)
x
=
globalPos
.
x
view
=
swipeView
.
takeItem
(
index
);
if
(
wasNeverVisible
){
width
=
view
.
width
;
y
=
globalPos
.
y
+
view
.
visibleChildren
[
0
].
height
+
15
/*margin + spacing*/
;
}
view
.
inOwnWindow
=
true
;
if
(
wasNeverVisible
)
height
=
Math
.
min
(
view
.
height
,
view
.
implicitHeight
);
visible
=
true
;
insertAtIndex
=
index
;
button
=
tabBar
.
takeItem
(
index
);
}
onClosing
:
{
view
.
inOwnWindow
=
false
;
swipeView
.
insertItem
(
insertAtIndex
,
view
);
tabBar
.
insertItem
(
insertAtIndex
,
button
);
}
}
Dialog
{
modal
:
true
title
:
"
Error
"
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment