Implemented basic functionality
This commit is contained in:
49
CMakeLists.txt
Normal file
49
CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(lightcontrol VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.2 REQUIRED COMPONENTS SerialPort Quick)
|
||||
|
||||
qt_add_executable(applightcontrol
|
||||
main.cpp
|
||||
devicetypesmodel.h devicetypesmodel.cpp
|
||||
dmxcontroller.h dmxcontroller.cpp
|
||||
dmxcontrollerthread.h dmxcontrollerthread.cpp
|
||||
lightproject.h lightproject.cpp
|
||||
devicesmodel.h devicesmodel.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(applightcontrol
|
||||
URI lightcontrol
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
main.qml
|
||||
main-dev.qml
|
||||
HomePage.qml
|
||||
SettingsPage.qml
|
||||
LightControlWindow.qml
|
||||
EditableListView.qml
|
||||
DeviceTypesSettingsPage.qml
|
||||
DevicesSettingsPage.qml
|
||||
)
|
||||
|
||||
set_target_properties(applightcontrol PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(applightcontrol
|
||||
PRIVATE
|
||||
Qt6::SerialPort
|
||||
Qt6::Quick
|
||||
)
|
||||
|
||||
install(TARGETS applightcontrol
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
60
DeviceTypesSettingsPage.qml
Normal file
60
DeviceTypesSettingsPage.qml
Normal file
@ -0,0 +1,60 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
text: qsTr("Device Types Settings")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
//Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
EditableListView {
|
||||
id: listView
|
||||
|
||||
Layout.preferredWidth: 300
|
||||
Layout.maximumWidth: 300
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: deviceTypesModel
|
||||
|
||||
onAddClicked: (index) => console.log('added', index);
|
||||
onRemoveClicked: (index) => deviceTypesModel.removeRow(index)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
GridLayout {
|
||||
Layout.preferredWidth: 300
|
||||
Layout.maximumWidth: 300
|
||||
|
||||
columns: 2
|
||||
|
||||
Label { text: qsTr("Id:") }
|
||||
SpinBox {
|
||||
Layout.fillWidth: true
|
||||
value: listView.currentItem.myData.id
|
||||
onValueModified: listView.currentItem.myData.id = value
|
||||
}
|
||||
Label { text: qsTr("Name:") }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
text: listView.currentItem.myData.name
|
||||
onTextEdited: listView.currentItem.myData.name = text
|
||||
}
|
||||
Label { text: qsTr("Registers:") }
|
||||
Pane {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
EditableListView {
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
67
DevicesSettingsPage.qml
Normal file
67
DevicesSettingsPage.qml
Normal file
@ -0,0 +1,67 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
text: qsTr("Devices Settings")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
//Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
EditableListView {
|
||||
id: listView
|
||||
|
||||
Layout.preferredWidth: 300
|
||||
Layout.maximumWidth: 300
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: devicesModel
|
||||
|
||||
onAddClicked: (index) => console.log('added', index)
|
||||
onRemoveClicked: (index) => devicesModel.removeRow(index)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
GridLayout {
|
||||
Layout.preferredWidth: 300
|
||||
Layout.maximumWidth: 300
|
||||
|
||||
columns: 2
|
||||
|
||||
Label { text: qsTr("Id:") }
|
||||
SpinBox {
|
||||
Layout.fillWidth: true
|
||||
value: listView.currentItem.myData.id
|
||||
onValueModified: listView.currentItem.myData.id = value
|
||||
}
|
||||
Label { text: qsTr("Name:") }
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
text: listView.currentItem.myData.name
|
||||
onTextEdited: listView.currentItem.myData.name = text
|
||||
}
|
||||
Label { text: qsTr("DeviceType:") }
|
||||
ComboBox {
|
||||
Layout.fillWidth: true
|
||||
model: deviceTypesModel
|
||||
textRole: "name"
|
||||
valueRole: "id"
|
||||
// TODO
|
||||
}
|
||||
Label { text: qsTr("Address:") }
|
||||
SpinBox {
|
||||
Layout.fillWidth: true
|
||||
value: listView.currentItem.myData.address
|
||||
onValueModified: listView.currentItem.myData.address = value
|
||||
}
|
||||
Label { text: qsTr("Position:") }
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
EditableListView.qml
Normal file
72
EditableListView.qml
Normal file
@ -0,0 +1,72 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
ColumnLayout {
|
||||
property alias model: listView.model
|
||||
property alias currentIndex: listView.currentIndex
|
||||
property alias currentItem: listView.currentItem
|
||||
|
||||
signal addClicked(index: int)
|
||||
signal removeClicked(index: int)
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Button {
|
||||
text: qsTr("Add")
|
||||
|
||||
onClicked: addClicked(listView.currentIndex)
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Remove")
|
||||
|
||||
onClicked: removeClicked(listView.currentIndex)
|
||||
enabled: listView.currentIndex >= 0
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
clip: true
|
||||
spacing: 2
|
||||
|
||||
delegate: Rectangle {
|
||||
property variant myData: model
|
||||
|
||||
width: listView.width
|
||||
height: 40
|
||||
|
||||
color: ListView.isCurrentItem ?
|
||||
Material.color(Material.Purple) :
|
||||
Material.color(Material.Purple, Material.Shade900)
|
||||
radius: 5
|
||||
|
||||
Label {
|
||||
anchors.fill: parent
|
||||
//anchors.verticalCenter: parent.verticalCenter
|
||||
id: text
|
||||
text: model.name
|
||||
padding: 5
|
||||
fontSizeMode: Text.VerticalFit
|
||||
minimumPixelSize: 10;
|
||||
font.pixelSize: 72
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: listView.currentIndex = index
|
||||
}
|
||||
}
|
||||
focus: true
|
||||
}
|
||||
}
|
71
HomePage.qml
Normal file
71
HomePage.qml
Normal file
@ -0,0 +1,71 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Flow {
|
||||
anchors.centerIn: parent
|
||||
|
||||
Repeater {
|
||||
model: devicesModel
|
||||
|
||||
ColumnLayout {
|
||||
width: 50
|
||||
height: 200
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: index
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: slider
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
orientation: Qt.Vertical
|
||||
from: 0
|
||||
to: 255
|
||||
|
||||
onValueChanged: __controller.setChannel(32 + index, value)
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: Math.round(slider.value)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.preferredWidth: 100
|
||||
Layout.fillHeight: true
|
||||
|
||||
Button {
|
||||
Layout.preferredHeight: 100
|
||||
|
||||
text: qsTr('Settings')
|
||||
|
||||
onClicked: stackview.push(settingsPage)
|
||||
|
||||
Component {
|
||||
id: settingsPage
|
||||
|
||||
SettingsPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
189
LightControlWindow.qml
Normal file
189
LightControlWindow.qml
Normal file
@ -0,0 +1,189 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import QtQuick.VirtualKeyboard
|
||||
|
||||
import com.büro 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
width: 1360
|
||||
height: 768
|
||||
title: qsTr("Hello World")
|
||||
|
||||
Material.theme: Material.Dark
|
||||
Material.accent: Material.Purple
|
||||
|
||||
DeviceTypesModel {
|
||||
id: deviceTypesModel
|
||||
controller: __controller
|
||||
}
|
||||
|
||||
DevicesModel {
|
||||
id: devicesModel
|
||||
controller: __controller
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Pane {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 75
|
||||
|
||||
Material.elevation: 6
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
text: qsTr("Schein-Commander")
|
||||
fontSizeMode: Text.VerticalFit
|
||||
minimumPixelSize: 10;
|
||||
font.pixelSize: 72
|
||||
}
|
||||
|
||||
Label {
|
||||
id: timeText
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
text: Qt.formatTime(new Date(), "hh:mm:ss")
|
||||
fontSizeMode: Text.VerticalFit
|
||||
minimumPixelSize: 10;
|
||||
font.pixelSize: 72
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 1000
|
||||
repeat: true
|
||||
running: true
|
||||
|
||||
onTriggered: timeText.text = Qt.formatTime(new Date(), "hh:mm:ss");
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillHeight: true
|
||||
|
||||
text: qsTr("Back")
|
||||
|
||||
onClicked: stackview.pop();
|
||||
enabled: stackview.depth > 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackView {
|
||||
id: stackview
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
initialItem: homePage
|
||||
|
||||
Component {
|
||||
id: homePage
|
||||
|
||||
HomePage {
|
||||
}
|
||||
}
|
||||
|
||||
pushEnter: Transition {
|
||||
PropertyAnimation {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to:1
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
pushExit: Transition {
|
||||
PropertyAnimation {
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to:0
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
popEnter: Transition {
|
||||
PropertyAnimation {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to:1
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
popExit: Transition {
|
||||
PropertyAnimation {
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to:0
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: closeButton
|
||||
|
||||
visible: inputPanel.active
|
||||
|
||||
anchors.bottom: inputPanel.top
|
||||
anchors.right: parent.right
|
||||
z: 99
|
||||
|
||||
//onClicked: inputPanel.active = false
|
||||
// onClicked: InputContext.priv.hideInputPanel()
|
||||
|
||||
text: qsTr("Close keyboard?")
|
||||
|
||||
focus: false
|
||||
}
|
||||
|
||||
InputPanel {
|
||||
id: inputPanel
|
||||
z: 99
|
||||
x: 0
|
||||
y: window.height
|
||||
width: window.width
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: inputPanel.active
|
||||
PropertyChanges {
|
||||
target: inputPanel
|
||||
y: window.height - inputPanel.height
|
||||
}
|
||||
}
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
reversible: false
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 1000
|
||||
easing.type: Easing.OutBounce
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
reversible: false
|
||||
ParallelAnimation {
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 1000
|
||||
easing.type: Easing.OutBounce
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
10
README.md
10
README.md
@ -1,2 +1,12 @@
|
||||
# scheincommander
|
||||
A qt quick application to control dmx moving heads / lights / fog machines (running on a raspberry pi)
|
||||
|
||||
## How to build
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
qmake6 ..
|
||||
make -j4096
|
||||
./applightcontrol
|
||||
```
|
||||
|
47
SettingsPage.qml
Normal file
47
SettingsPage.qml
Normal file
@ -0,0 +1,47 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
Label {
|
||||
text: qsTr("Settings")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
|
||||
Button {
|
||||
id: button0
|
||||
text: qsTr("Device\nTypes")
|
||||
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: 100
|
||||
|
||||
onClicked: stackview.push(deviceTypesSettingsPage)
|
||||
|
||||
Component {
|
||||
id: deviceTypesSettingsPage
|
||||
|
||||
DeviceTypesSettingsPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button1
|
||||
text: qsTr("Devices")
|
||||
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: 100
|
||||
|
||||
onClicked: stackview.push(devicesSettingsPage)
|
||||
|
||||
Component {
|
||||
id: devicesSettingsPage
|
||||
|
||||
DevicesSettingsPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
280
devicesmodel.cpp
Normal file
280
devicesmodel.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
#include "devicesmodel.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlEngine>
|
||||
|
||||
constexpr auto IdRole = Qt::UserRole;
|
||||
constexpr auto LightTypeIdRole = Qt::UserRole + 1;
|
||||
constexpr auto AddressRole = Qt::UserRole + 2;
|
||||
constexpr auto PositionRole = Qt::UserRole + 3;
|
||||
|
||||
DevicesModel::DevicesModel(QObject *parent) :
|
||||
QAbstractItemModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void DevicesModel::setController(DmxController *controller)
|
||||
{
|
||||
if (m_controller != controller)
|
||||
{
|
||||
beginResetModel();
|
||||
m_controller = controller;
|
||||
endResetModel();
|
||||
emit controllerChanged(m_controller);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex DevicesModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
||||
QModelIndex DevicesModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int DevicesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
return 0;
|
||||
|
||||
return m_controller->lightProject().lights.size();
|
||||
}
|
||||
|
||||
int DevicesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant DevicesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() < 0 || index.row() >= m_controller->lightProject().lights.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &light = m_controller->lightProject().lights.at(index.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole: return light.name;
|
||||
case IdRole: return light.id;
|
||||
case LightTypeIdRole: return light.lightTypeId;
|
||||
case AddressRole: return light.address;
|
||||
case PositionRole: return light.position;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QMap<int, QVariant> DevicesModel::itemData(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() < 0 || index.row() >= m_controller->lightProject().lights.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &light = m_controller->lightProject().lights.at(index.row());
|
||||
|
||||
return {
|
||||
{ Qt::DisplayRole, light.name },
|
||||
{ IdRole, light.id },
|
||||
{ LightTypeIdRole, light.lightTypeId },
|
||||
{ AddressRole, light.address },
|
||||
{ PositionRole, light.position }
|
||||
};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> DevicesModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{ Qt::DisplayRole, "name" },
|
||||
{ IdRole, "id" },
|
||||
{ LightTypeIdRole, "lightTypeId" },
|
||||
{ AddressRole, "address" },
|
||||
{ PositionRole, "position" }
|
||||
};
|
||||
}
|
||||
|
||||
bool DevicesModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &lights = m_controller->lightProject().lights;
|
||||
if (index.row() < 0 || index.row() >= lights.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &light = lights.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
if (value.userType() != QMetaType::QString)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
light.name = value.toString();
|
||||
emit dataChanged(index, index, { Qt::DisplayRole, Qt::EditRole });
|
||||
return true;
|
||||
case IdRole:
|
||||
if (value.userType() != QMetaType::Int)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
light.id = value.toInt();
|
||||
emit dataChanged(index, index, { IdRole });
|
||||
return true;
|
||||
case LightTypeIdRole:
|
||||
if (value.userType() != QMetaType::Int)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
light.lightTypeId = value.toInt();
|
||||
emit dataChanged(index, index, { LightTypeIdRole });
|
||||
return true;
|
||||
case AddressRole:
|
||||
if (value.userType() != QMetaType::Int)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
light.address = value.toInt();
|
||||
emit dataChanged(index, index, { AddressRole });
|
||||
return true;
|
||||
case PositionRole:
|
||||
if (value.userType() != QMetaType::QVector3D)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
light.position = value.value<QVector3D>();
|
||||
emit dataChanged(index, index, { AddressRole });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevicesModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &lights = m_controller->lightProject().lights;
|
||||
|
||||
if (row >= lights.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (row + count >= lights.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
beginRemoveRows({}, row, row+count-1);
|
||||
auto begin = std::begin(lights) + row;
|
||||
auto end = begin + count;
|
||||
lights.erase(begin, end);
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void registerDenShit()
|
||||
{
|
||||
qmlRegisterType<DevicesModel>("com.büro", 1, 0, "DevicesModel");
|
||||
}
|
||||
}
|
||||
Q_COREAPP_STARTUP_FUNCTION(registerDenShit)
|
35
devicesmodel.h
Normal file
35
devicesmodel.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "dmxcontroller.h"
|
||||
|
||||
class DevicesModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(DmxController* controller READ controller WRITE setController NOTIFY controllerChanged)
|
||||
|
||||
public:
|
||||
explicit DevicesModel(QObject *parent = nullptr);
|
||||
|
||||
DmxController *controller() { return m_controller; }
|
||||
const DmxController *controller() const { return m_controller; }
|
||||
void setController(DmxController *controller);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QMap<int, QVariant> itemData(const QModelIndex &index) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
||||
|
||||
signals:
|
||||
void controllerChanged(DmxController *controller);
|
||||
|
||||
private:
|
||||
DmxController *m_controller{};
|
||||
};
|
241
devicetypesmodel.cpp
Normal file
241
devicetypesmodel.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include "devicetypesmodel.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlEngine>
|
||||
|
||||
constexpr auto IdRole = Qt::UserRole;
|
||||
|
||||
DeviceTypesModel::DeviceTypesModel(QObject *parent) :
|
||||
QAbstractItemModel{parent}
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceTypesModel::setController(DmxController *controller)
|
||||
{
|
||||
if (m_controller != controller)
|
||||
{
|
||||
beginResetModel();
|
||||
m_controller = controller;
|
||||
endResetModel();
|
||||
emit controllerChanged(m_controller);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex DeviceTypesModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
||||
QModelIndex DeviceTypesModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int DeviceTypesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
return 0;
|
||||
|
||||
return m_controller->lightProject().lightTypes.size();
|
||||
}
|
||||
|
||||
int DeviceTypesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant DeviceTypesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() < 0 || index.row() >= m_controller->lightProject().lightTypes.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &lightType = m_controller->lightProject().lightTypes.at(index.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole: return lightType.name;
|
||||
case IdRole: return lightType.id;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QMap<int, QVariant> DeviceTypesModel::itemData(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.row() < 0 || index.row() >= m_controller->lightProject().lightTypes.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &lightType = m_controller->lightProject().lightTypes.at(index.row());
|
||||
|
||||
return {
|
||||
{ Qt::DisplayRole, lightType.name },
|
||||
{ IdRole, lightType.id }
|
||||
};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> DeviceTypesModel::roleNames() const
|
||||
{
|
||||
return {
|
||||
{ Qt::DisplayRole, "name" },
|
||||
{ IdRole, "id" }
|
||||
};
|
||||
}
|
||||
|
||||
bool DeviceTypesModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &lightTypes = m_controller->lightProject().lightTypes;
|
||||
if (index.row() < 0 || index.row() >= lightTypes.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index.column() != 0)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &lightType = lightTypes.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
if (value.userType() != QMetaType::QString)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
lightType.name = value.toString();
|
||||
emit dataChanged(index, index, { Qt::DisplayRole, Qt::EditRole });
|
||||
return true;
|
||||
case IdRole:
|
||||
if (value.userType() != QMetaType::Int)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__ << value.userType();
|
||||
return false;
|
||||
}
|
||||
lightType.id = value.toInt();
|
||||
emit dataChanged(index, index, { IdRole });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceTypesModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_controller)
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto &lightTypes = m_controller->lightProject().lightTypes;
|
||||
|
||||
if (row >= lightTypes.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (row + count > lightTypes.size())
|
||||
{
|
||||
qWarning() << "hilfe" << __LINE__;
|
||||
return false;
|
||||
}
|
||||
|
||||
beginRemoveRows({}, row, row+count-1);
|
||||
auto begin = std::begin(lightTypes) + row;
|
||||
auto end = begin + count;
|
||||
lightTypes.erase(begin, end);
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void registerDenShit()
|
||||
{
|
||||
qmlRegisterType<DeviceTypesModel>("com.büro", 1, 0, "DeviceTypesModel");
|
||||
}
|
||||
}
|
||||
Q_COREAPP_STARTUP_FUNCTION(registerDenShit)
|
35
devicetypesmodel.h
Normal file
35
devicetypesmodel.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "dmxcontroller.h"
|
||||
|
||||
class DeviceTypesModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(DmxController* controller READ controller WRITE setController NOTIFY controllerChanged)
|
||||
|
||||
public:
|
||||
explicit DeviceTypesModel(QObject *parent = nullptr);
|
||||
|
||||
DmxController *controller() { return m_controller; }
|
||||
const DmxController *controller() const { return m_controller; }
|
||||
void setController(DmxController *controller);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QMap<int, QVariant> itemData(const QModelIndex &index) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
||||
|
||||
signals:
|
||||
void controllerChanged(DmxController *controller);
|
||||
|
||||
private:
|
||||
DmxController *m_controller{};
|
||||
};
|
109
dmxcontroller.cpp
Normal file
109
dmxcontroller.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include "dmxcontroller.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
DmxController::DmxController(QObject *parent) :
|
||||
QObject{parent},
|
||||
m_thread{*this},
|
||||
m_lastInfo{QDateTime::currentDateTime()},
|
||||
m_counter{},
|
||||
m_lightProject {
|
||||
.lightTypes {
|
||||
{ .id=0, .name="Stairville MH-X50+" },
|
||||
{ .id=1, .name="RGBW Strahler" },
|
||||
{ .id=2, .name="RGB Strahler" },
|
||||
{ .id=3, .name="Nebelmaschine" }
|
||||
},
|
||||
.lights {
|
||||
{ .id=0, .name="Lampe 1", .lightTypeId=1, .address=32 },
|
||||
{ .id=1, .name="Lampe 2", .lightTypeId=1, .address=0 },
|
||||
{ .id=2, .name="Lampe 3", .lightTypeId=1, .address=7 },
|
||||
{ .id=3, .name="Lampe 4", .lightTypeId=1, .address=14 },
|
||||
{ .id=4, .name="Moving Head 1", .lightTypeId=0, .address=40 },
|
||||
{ .id=5, .name="Moving Head 2", .lightTypeId=0, .address=43 },
|
||||
{ .id=6, .name="Moving Head 3", .lightTypeId=0, .address=46 },
|
||||
{ .id=7, .name="Moving Head 4", .lightTypeId=0, .address=49 },
|
||||
{ .id=8, .name="Test 1", .lightTypeId=2, .address=70 },
|
||||
{ .id=9, .name="Test 2", .lightTypeId=2, .address=72 },
|
||||
{ .id=10, .name="Nebelmaschine", .lightTypeId=3, .address=80 }
|
||||
}
|
||||
}
|
||||
{
|
||||
std::fill(std::begin(buf), std::end(buf), 0);
|
||||
|
||||
buf[32] = 255;
|
||||
buf[33] = 255;
|
||||
buf[34] = 0;
|
||||
buf[35] = 0;
|
||||
// buf[36] = 255;
|
||||
}
|
||||
|
||||
bool DmxController::start()
|
||||
{
|
||||
m_serialPort.setPortName("/dev/ttyAMA0");
|
||||
if (!m_serialPort.setBaudRate(250000))
|
||||
{
|
||||
qCritical("setBaudRate() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (!m_serialPort.setDataBits(QSerialPort::Data8))
|
||||
{
|
||||
qCritical("setDataBits() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (!m_serialPort.setParity(QSerialPort::NoParity))
|
||||
{
|
||||
qCritical("setParity() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (!m_serialPort.setStopBits(QSerialPort::TwoStop))
|
||||
{
|
||||
qCritical("setStopBits() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (!m_serialPort.setFlowControl(QSerialPort::NoFlowControl))
|
||||
{
|
||||
qCritical("setFlowControl() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (!m_serialPort.open(QIODevice::WriteOnly))
|
||||
{
|
||||
qCritical("open() failed %s", qPrintable(m_serialPort.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_thread.start(QThread::TimeCriticalPriority);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DmxController::setChannel(int channel, int value)
|
||||
{
|
||||
buf[channel] = value;
|
||||
}
|
||||
|
||||
void DmxController::sendDmxBuffer()
|
||||
{
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
|
||||
m_serialPort.setBreakEnabled(true);
|
||||
QThread::usleep(88);
|
||||
m_serialPort.setBreakEnabled(false);
|
||||
|
||||
// const auto written = write(m_serialPort.handle(), buf, std::size(buf));
|
||||
const auto written = m_serialPort.write(buf, std::size(buf));
|
||||
m_serialPort.flush();
|
||||
// qDebug("%lli written", written);
|
||||
|
||||
m_counter++;
|
||||
|
||||
if (m_lastInfo.msecsTo(now) >= 1000)
|
||||
{
|
||||
qInfo("%i per second ä", m_counter);
|
||||
m_counter = 0;
|
||||
m_lastInfo = now;
|
||||
}
|
||||
}
|
44
dmxcontroller.h
Normal file
44
dmxcontroller.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
#include <QDateTime>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include "dmxcontrollerthread.h"
|
||||
#include "lightproject.h"
|
||||
|
||||
class DmxController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DmxController(QObject *parent = nullptr);
|
||||
|
||||
bool start();
|
||||
|
||||
Q_INVOKABLE void setChannel(int channel, int value);
|
||||
|
||||
LightProject &lightProject() { return m_lightProject; }
|
||||
const LightProject &lightProject() const { return m_lightProject; }
|
||||
|
||||
QReadWriteLock &projectLock() { return m_projectLock; }
|
||||
|
||||
protected:
|
||||
friend class DmxControllerThread;
|
||||
|
||||
void sendDmxBuffer(); // runs in its own thread
|
||||
|
||||
private:
|
||||
QSerialPort m_serialPort;
|
||||
|
||||
DmxControllerThread m_thread;
|
||||
|
||||
char buf[513];
|
||||
|
||||
LightProject m_lightProject;
|
||||
QReadWriteLock m_projectLock;
|
||||
|
||||
QDateTime m_lastInfo;
|
||||
int m_counter;
|
||||
};
|
15
dmxcontrollerthread.cpp
Normal file
15
dmxcontrollerthread.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "dmxcontrollerthread.h"
|
||||
|
||||
#include "dmxcontroller.h"
|
||||
|
||||
DmxControllerThread::DmxControllerThread(DmxController &controller) :
|
||||
QThread{&controller},
|
||||
m_controller{controller}
|
||||
{
|
||||
}
|
||||
|
||||
void DmxControllerThread::run()
|
||||
{
|
||||
while (!isInterruptionRequested())
|
||||
m_controller.sendDmxBuffer();
|
||||
}
|
18
dmxcontrollerthread.h
Normal file
18
dmxcontrollerthread.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <QThread>
|
||||
|
||||
class DmxController;
|
||||
|
||||
class DmxControllerThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DmxControllerThread(DmxController &controller);
|
||||
|
||||
void run() override;
|
||||
|
||||
private:
|
||||
DmxController &m_controller;
|
||||
};
|
1
lightproject.cpp
Normal file
1
lightproject.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "lightproject.h"
|
27
lightproject.h
Normal file
27
lightproject.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QString>
|
||||
#include <QVector3D>
|
||||
|
||||
struct LightTypeConfig
|
||||
{
|
||||
int id;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct LightConfig
|
||||
{
|
||||
int id;
|
||||
QString name;
|
||||
int lightTypeId;
|
||||
int address;
|
||||
QVector3D position;
|
||||
};
|
||||
|
||||
struct LightProject
|
||||
{
|
||||
std::vector<LightTypeConfig> lightTypes;
|
||||
std::vector<LightConfig> lights;
|
||||
};
|
5
main-dev.qml
Normal file
5
main-dev.qml
Normal file
@ -0,0 +1,5 @@
|
||||
import QtQuick
|
||||
|
||||
LightControlWindow {
|
||||
visible: true
|
||||
}
|
61
main.cpp
Normal file
61
main.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QDebug>
|
||||
|
||||
#include "dmxcontroller.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
qSetMessagePattern(QStringLiteral("%{time dd.MM.yyyy HH:mm:ss.zzz} "
|
||||
"["
|
||||
"%{if-debug}D%{endif}"
|
||||
"%{if-info}I%{endif}"
|
||||
"%{if-warning}W%{endif}"
|
||||
"%{if-critical}C%{endif}"
|
||||
"%{if-fatal}F%{endif}"
|
||||
"] "
|
||||
"%{function}(): "
|
||||
"%{message}"));
|
||||
|
||||
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
|
||||
|
||||
QGuiApplication app{argc, argv};
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
QCommandLineOption windowedOption {
|
||||
QStringList{"w", "windowed"},
|
||||
QCoreApplication::translate("main", "Show in windowed (only dev)")
|
||||
};
|
||||
parser.addOption(windowedOption);
|
||||
|
||||
if (!parser.parse(app.arguments()))
|
||||
{
|
||||
qFatal("could not parse arguments!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const auto windowed = parser.isSet(windowedOption);
|
||||
|
||||
DmxController controller{&app};
|
||||
if (!controller.start() && !windowed)
|
||||
return -1;
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
engine.rootContext()->setContextProperty("__controller", &controller);
|
||||
|
||||
const QUrl url{windowed ? u"qrc:/lightcontrol/main-dev.qml"_qs : u"qrc:/lightcontrol/main.qml"_qs};
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
engine.load(url);
|
||||
|
||||
return app.exec();
|
||||
}
|
Reference in New Issue
Block a user