Added: Connection Config, Chart, Improved: Connection Handling, Controller
This commit is contained in:
parent
c48b714490
commit
470511ceab
16 changed files with 979 additions and 25 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
build/
|
||||
CMakeLists.txt.user
|
||||
|
|
|
|||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "qt_zoomable_chart_widget"]
|
||||
path = qt_zoomable_chart_widget
|
||||
url = https://github.com/martonmiklos/qt_zoomable_chart_widget.git
|
||||
[submodule "QtWaitingSpinner"]
|
||||
path = QtWaitingSpinner
|
||||
url = https://github.com/snowwlex/QtWaitingSpinner.git
|
||||
|
|
@ -10,8 +10,10 @@ set(CMAKE_AUTORCC ON)
|
|||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Network Core5Compat)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network Core5Compat)
|
||||
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Network Core5Compat Charts)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network Core5Compat Charts)
|
||||
|
||||
add_subdirectory(qt_zoomable_chart_widget/)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
|
|
@ -20,12 +22,21 @@ set(PROJECT_SOURCES
|
|||
mainwindow.ui
|
||||
shimlccontroller.cpp
|
||||
shimlccontroller.h
|
||||
connectionconfiguration.cpp
|
||||
connectionconfiguration.h
|
||||
qt_zoomable_chart_widget/res/zoomable_chart_widget_resources.qrc
|
||||
QtWaitingSpinner/waitingspinnerwidget.cpp
|
||||
QtWaitingSpinner/waitingspinnerwidget.h
|
||||
)
|
||||
|
||||
|
||||
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
qt_add_executable(QtChroma
|
||||
MANUAL_FINALIZATION
|
||||
${PROJECT_SOURCES}
|
||||
systemconfiguration.h systemconfiguration.cpp systemconfiguration.ui
|
||||
connectionconfiguration.h connectionconfiguration.cpp connectionconfiguration.ui
|
||||
|
||||
)
|
||||
# Define target properties for Android with Qt 6 as:
|
||||
# set_property(TARGET QtChroma APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||
|
|
@ -46,7 +57,7 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(QtChroma PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Core5Compat)
|
||||
target_link_libraries(QtChroma PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Core5Compat Qt${QT_VERSION_MAJOR}::Charts zoomablechart)
|
||||
|
||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||
# If you are developing for iOS or macOS you should consider setting an
|
||||
|
|
@ -63,6 +74,8 @@ set_target_properties(QtChroma PROPERTIES
|
|||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
install(TARGETS QtChroma
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
|
|
|
|||
1
QtWaitingSpinner
Submodule
1
QtWaitingSpinner
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a1325a2ef1bac0ce37e9fe05d7be26554e33bba5
|
||||
40
connectionconfiguration.cpp
Normal file
40
connectionconfiguration.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#include "connectionconfiguration.h"
|
||||
#include "ui_connectionconfiguration.h"
|
||||
|
||||
ConnectionConfiguration::ConnectionConfiguration(QSettings *settings, ShimLCController *ctrl, QWidget *parent)
|
||||
: QDialog(parent), settings(settings), ctrl(ctrl)
|
||||
, ui(new Ui::ConnectionConfiguration)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->addrEntry->setText(settings->value("connection/addr", "localhost").toString());
|
||||
ui->portEntry->setValue(settings->value("connection/port", 5001).toInt());
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &ConnectionConfiguration::apply);
|
||||
}
|
||||
|
||||
ConnectionConfiguration::~ConnectionConfiguration()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConnectionConfiguration::apply()
|
||||
{
|
||||
settings->setValue("connection/addr", ui->addrEntry->text());
|
||||
settings->setValue("connection/port", ui->portEntry->value());
|
||||
ctrl->reconnect(settings);
|
||||
if(settings->value("connection/showInfo").toBool() == 0)
|
||||
switch( QMessageBox::information(
|
||||
this,
|
||||
tr("QtChroma"),
|
||||
tr("Connection settings changed!\r\nWill try to reconnect with new settings.\r\nShow this message again?"),
|
||||
|
||||
QMessageBox::Yes |
|
||||
QMessageBox::No,
|
||||
|
||||
QMessageBox::Yes ) )
|
||||
{
|
||||
case QMessageBox::No:
|
||||
settings->setValue("connection/showInfo", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
30
connectionconfiguration.h
Normal file
30
connectionconfiguration.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef CONNECTIONCONFIGURATION_H
|
||||
#define CONNECTIONCONFIGURATION_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "shimlccontroller.h"
|
||||
|
||||
namespace Ui {
|
||||
class ConnectionConfiguration;
|
||||
}
|
||||
|
||||
class ConnectionConfiguration : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionConfiguration(QSettings *settings, ShimLCController *ctrl, QWidget *parent);
|
||||
~ConnectionConfiguration();
|
||||
|
||||
private:
|
||||
Ui::ConnectionConfiguration *ui;
|
||||
void apply();
|
||||
QSettings *settings = nullptr;
|
||||
ShimLCController *ctrl = nullptr;
|
||||
void test();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONCONFIGURATION_H
|
||||
92
connectionconfiguration.ui
Normal file
92
connectionconfiguration.ui
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConnectionConfiguration</class>
|
||||
<widget class="QDialog" name="ConnectionConfiguration">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="addrEntry"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="portEntry">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ConnectionConfiguration</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ConnectionConfiguration</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -6,9 +6,62 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
mainChart = ui->chartWidget->chart();
|
||||
spinner = ui->spinner;
|
||||
connect(ui->actionConfiguration, SIGNAL(triggered()), &systemConfigWindow, SLOT(show()));
|
||||
connect(ui->actionConnConfiguration, SIGNAL(triggered()), &connConf, SLOT(show()));
|
||||
connect(&ctrl, &ShimLCController::connectionStateChanged, this, &MainWindow::updateConnectionState);
|
||||
|
||||
spinner->setRoundness(70.0);
|
||||
spinner->setMinimumTrailOpacity(15.0);
|
||||
spinner->setTrailFadePercentage(70.0);
|
||||
spinner->setNumberOfLines(12);
|
||||
spinner->setLineLength(10);
|
||||
spinner->setLineWidth(5);
|
||||
spinner->setInnerRadius(10);
|
||||
spinner->setRevolutionsPerSecond(1);
|
||||
spinner->setColor(QColor(81, 4, 71));
|
||||
|
||||
// Try to auto connect
|
||||
ui->frame->setEnabled(false);
|
||||
ctrl.reconnect(&settings);
|
||||
|
||||
mainChart->setTitle("Detector Data");
|
||||
//mainChart->setAnimationOptions(QChart::SeriesAnimations);
|
||||
|
||||
// Example...
|
||||
auto series = new QLineSeries;
|
||||
for (int i = 0; i < 500; i++) {
|
||||
QPointF p((qreal) i, qSin(M_PI / 50 * i) * 100);
|
||||
p.ry() += QRandomGenerator::global()->bounded(20);
|
||||
*series << p;
|
||||
}
|
||||
mainChart->addSeries(series);
|
||||
mainChart->createDefaultAxes();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::updateConnectionState(QAbstractSocket::SocketState state)
|
||||
{
|
||||
const QMetaObject & mo = QAbstractSocket::staticMetaObject;
|
||||
QMetaEnum me = mo.enumerator(mo.indexOfEnumerator("SocketState"));
|
||||
QString connectionString(me.valueToKey(state));
|
||||
ui->connState->setText("COM: "+connectionString);
|
||||
if(state == QAbstractSocket::ConnectingState)
|
||||
spinner->start();
|
||||
else
|
||||
spinner->stop();
|
||||
if(state == QAbstractSocket::ConnectedState)
|
||||
ui->frame->setEnabled(true);
|
||||
else
|
||||
ui->frame->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::initConnection()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
17
mainwindow.h
17
mainwindow.h
|
|
@ -2,7 +2,13 @@
|
|||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QSettings>
|
||||
#include "shimlccontroller.h"
|
||||
#include "systemconfiguration.h"
|
||||
#include "connectionconfiguration.h"
|
||||
#include "zoomablechart.h"
|
||||
#include "zoomablechartview.h"
|
||||
#include "QtWaitingSpinner/waitingspinnerwidget.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
|
|
@ -19,7 +25,16 @@ public:
|
|||
~MainWindow();
|
||||
|
||||
private:
|
||||
QSettings settings{"Greyhash", "QtChroma"};
|
||||
Ui::MainWindow *ui;
|
||||
ShimLCController foo{};
|
||||
ShimLCController ctrl{this};
|
||||
SystemConfiguration systemConfigWindow{&ctrl, this};
|
||||
ConnectionConfiguration connConf{&settings, &ctrl, this};
|
||||
ZoomableChart* mainChart = nullptr;
|
||||
WaitingSpinnerWidget* spinner = nullptr;
|
||||
|
||||
private slots:
|
||||
void updateConnectionState(QAbstractSocket::SocketState state);
|
||||
void initConnection();
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
442
mainwindow.ui
442
mainwindow.ui
|
|
@ -13,7 +13,401 @@
|
|||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>446</width>
|
||||
<height>170</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>800000</width>
|
||||
<height>170</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QComboBox" name="pumpsSelectorBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="pumpFlow"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ml/min</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>MPa</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLCDNumber" name="pumpPercent"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLCDNumber" name="pumpPress"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Hack</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pumps</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Hack</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autosampler</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="autoSamplerStatus">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>°C</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLCDNumber" name="lcdNumber"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Hack</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Detector</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="pumpsSelectorBox_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>mAU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLCDNumber" name="lcdNumber_2"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QDoubleSpinBox" name="pumpFlow_2"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>nm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>8000</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Hack</family>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>130</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="WaitingSpinnerWidget" name="spinner" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="connState">
|
||||
<property name="text">
|
||||
<string>Connection: X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ZoomableChartWidget" name="chartWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
|
|
@ -23,9 +417,55 @@
|
|||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuQtChroma">
|
||||
<property name="title">
|
||||
<string>System</string>
|
||||
</property>
|
||||
<addaction name="actionConfiguration"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuConnection">
|
||||
<property name="title">
|
||||
<string>Connection</string>
|
||||
</property>
|
||||
<addaction name="actionConnConfiguration"/>
|
||||
</widget>
|
||||
<addaction name="menuQtChroma"/>
|
||||
<addaction name="menuConnection"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionConfiguration">
|
||||
<property name="text">
|
||||
<string>Configuration</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="connectionState">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>State: Loading...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConnConfiguration">
|
||||
<property name="text">
|
||||
<string>Configuration</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ZoomableChartWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>zoomablechartwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>WaitingSpinnerWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>QtWaitingSpinner/waitingspinnerwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
1
qt_zoomable_chart_widget
Submodule
1
qt_zoomable_chart_widget
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f610926f0c4411dd34c836b1cb7f66ca3e1631eb
|
||||
|
|
@ -46,6 +46,7 @@ ShimTCPController::ShimTCPController(QObject *parent) : QObject(parent)
|
|||
|
||||
connect(socket, &QTcpSocket::readyRead, this, &ShimTCPController::readData);
|
||||
connect(socket, &QTcpSocket::errorOccurred, this, &ShimTCPController::displayError);
|
||||
connect(socket, &QTcpSocket::stateChanged, this, &ShimTCPController::emitConnectionStateChanged);
|
||||
connect(this, &ShimTCPController::dataAvailable, this, &ShimTCPController::dataAvailableErrorNoF);
|
||||
|
||||
}
|
||||
|
|
@ -57,11 +58,12 @@ ShimTCPController::~ShimTCPController()
|
|||
|
||||
void ShimTCPController::connectToHost(QString host)
|
||||
{
|
||||
// Close Connection
|
||||
qDebug() << TAG << "Connecting to host" << host;
|
||||
// Close Connection CAUTION: If currently waiting for response this could mess up the state machine in an infinte waiting loop, TODO: proper handeling
|
||||
socket->abort();
|
||||
// Connect TCP Socket Port 5001
|
||||
socket->connectToHost(host, 5001);
|
||||
socket->waitForConnected();
|
||||
//socket->waitForConnected();
|
||||
}
|
||||
|
||||
// Wirte and flush data if connected
|
||||
|
|
@ -75,39 +77,34 @@ bool ShimTCPController::writeData(QByteArray *data)
|
|||
}
|
||||
else
|
||||
{
|
||||
pendingData = new QByteArray(*data);
|
||||
qDebug() << TAG << "socket write Data sceduled when connection state changed to ConnectedState!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ShimTCPController::displayError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
// TODO: Proper centering by passing parent object!
|
||||
switch (socketError) {
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
break;
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
/*
|
||||
QMessageBox::information(this, tr("ShimLCController"),
|
||||
QMessageBox::information(nullptr, tr("ShimLCController"),
|
||||
tr("The host was not found. Please check the "
|
||||
"host name and port settings."));
|
||||
*/
|
||||
break;
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
/*
|
||||
QMessageBox::information(this, tr("ShimLCController"),
|
||||
QMessageBox::information(nullptr, tr("ShimLCController"),
|
||||
tr("The connection was refused by the peer."));
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/*
|
||||
QMessageBox::information(this, tr("ShimLCController"),
|
||||
QMessageBox::information(nullptr, tr("ShimLCController"),
|
||||
tr("The following error occurred: %1.")
|
||||
.arg(tcpSocket->errorString()));
|
||||
*/
|
||||
.arg(socket->errorString()));
|
||||
break;
|
||||
}
|
||||
qDebug() << socketError;
|
||||
|
||||
//getFortuneButton->setEnabled(true);
|
||||
}
|
||||
|
||||
// Parse Data and reset parserFunction signal
|
||||
|
|
@ -194,6 +191,18 @@ void ShimTCPController::dataAvailableErrorNoF(QByteArray data)
|
|||
qDebug() << data;
|
||||
}
|
||||
|
||||
void ShimTCPController::emitConnectionStateChanged()
|
||||
{
|
||||
QAbstractSocket::SocketState state = socket->state();
|
||||
if(state == QAbstractSocket::ConnectedState and (pendingData != nullptr))
|
||||
{
|
||||
writeData(pendingData);
|
||||
delete pendingData;
|
||||
qDebug() << "pendng data sent!";
|
||||
}
|
||||
emit connectionStateChanged(state);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
float QByteArrayToFloatBE(QByteArray arr)
|
||||
|
|
@ -217,12 +226,12 @@ float QByteArrayToFloatLE(QByteArray arr)
|
|||
}
|
||||
|
||||
ShimLCCommandStack::ShimLCCommandStack(QObject *parent)
|
||||
:parent(parent)
|
||||
{
|
||||
disconnect(&connection, &ShimTCPController::dataAvailable, 0, 0);
|
||||
connect(&connection, &ShimTCPController::dataAvailable, this, &ShimLCCommandStack::newResult);
|
||||
connect(&connection, &ShimTCPController::irDone, this, &ShimLCCommandStack::exitedIr);
|
||||
|
||||
connection.connectToHost("192.168.200.99");
|
||||
connect(&connection, &ShimTCPController::connectionStateChanged, this, &ShimLCCommandStack::connectionStateChanged);
|
||||
}
|
||||
|
||||
ShimLCCommandStack::~ShimLCCommandStack()
|
||||
|
|
@ -232,8 +241,10 @@ ShimLCCommandStack::~ShimLCCommandStack()
|
|||
|
||||
uint32_t ShimLCCommandStack::addCmd(char opcode, QString cmd, QByteArray* dest)
|
||||
{
|
||||
qDebug() << TAG << "added cmd: Opcode:" << opcode << "Cmd:" << cmd;
|
||||
id ++;
|
||||
stackIn.push_back(ShimLCCmd{id, opcode, cmd, dest});
|
||||
qDebug() << TAG << "Current size of cmd stack:" << stackIn.size();
|
||||
if(busy_id == 0)
|
||||
this->next();
|
||||
return id;
|
||||
|
|
@ -310,6 +321,12 @@ uint32_t ShimLCCommandStack::iCmd(QString cmd, QByteArray* dest)
|
|||
return addCmd(opcode, cmd, dest);
|
||||
}
|
||||
|
||||
void ShimLCCommandStack::reconnect(QSettings *settings)
|
||||
{
|
||||
// TODO: PORT!
|
||||
connection.connectToHost(settings->value("connection/addr", "localhost").toString());
|
||||
}
|
||||
|
||||
void ShimLCCommandStack::exitedIr()
|
||||
{
|
||||
emit dataAvailable(busy_id);
|
||||
|
|
@ -332,10 +349,14 @@ void ShimLCController::updateStatus()
|
|||
ids[ID_STATUS] = cmd.iCmd("OR lmon.", &data);
|
||||
}
|
||||
|
||||
void ShimLCController::reconnect(QSettings *settings)
|
||||
{
|
||||
cmd.reconnect(settings);
|
||||
}
|
||||
|
||||
ShimLCController::ShimLCController(QObject *parent)
|
||||
{
|
||||
updateConfig();
|
||||
updateStatus();
|
||||
connect(&cmd, &ShimLCCommandStack::connectionStateChanged, this, &ShimLCController::connectionStateChanged);
|
||||
}
|
||||
|
||||
ShimLCController::~ShimLCController()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include <QList>
|
||||
#include <tuple>
|
||||
#include <cmath>
|
||||
#include <QAbstractSocket>
|
||||
#include <QMessageBox>
|
||||
|
||||
struct ShimLCCmdStackResult
|
||||
{
|
||||
|
|
@ -39,6 +41,7 @@ private slots:
|
|||
void parseCbmIr();
|
||||
|
||||
void dataAvailableErrorNoF(QByteArray data);
|
||||
void emitConnectionStateChanged();
|
||||
|
||||
public slots:
|
||||
void connectToHost(QString host);
|
||||
|
|
@ -46,12 +49,15 @@ public slots:
|
|||
signals:
|
||||
void irDone();
|
||||
void dataAvailable(QByteArray data);
|
||||
void connectionStateChanged(QAbstractSocket::SocketState state);
|
||||
|
||||
private:
|
||||
QString TAG = "ShimTCPController";
|
||||
QTcpSocket *socket;
|
||||
QByteArray next_pkg{};
|
||||
int irMode = 0;
|
||||
QByteArray* irData = nullptr;
|
||||
QByteArray* pendingData = nullptr;
|
||||
};
|
||||
|
||||
// ---
|
||||
|
|
@ -66,6 +72,7 @@ private slots:
|
|||
|
||||
signals:
|
||||
void dataAvailable(uint32_t id);
|
||||
void connectionStateChanged(QAbstractSocket::SocketState state);
|
||||
|
||||
public:
|
||||
explicit ShimLCCommandStack(QObject *parent = 0);
|
||||
|
|
@ -74,9 +81,11 @@ public:
|
|||
uint32_t getSetVal(QString cmd, QByteArray *dest);
|
||||
uint32_t getActVal(QString cmd, QByteArray *dest);
|
||||
uint32_t iCmd(QString cmd, QByteArray *dest);
|
||||
void reconnect(QSettings *settings);
|
||||
|
||||
private:
|
||||
|
||||
QString TAG = "ShimLCCommandStack";
|
||||
using Connection = std::tuple<QObject*, const char*>;
|
||||
struct ShimLCCmd
|
||||
{
|
||||
|
|
@ -94,6 +103,8 @@ private:
|
|||
|
||||
void next();
|
||||
uint32_t addCmd(char opcode, QString cmd, QByteArray* dest);
|
||||
|
||||
QObject* parent;
|
||||
};
|
||||
|
||||
// ---
|
||||
|
|
@ -214,6 +225,8 @@ class ShimLCController : public QObject
|
|||
public:
|
||||
void updateConfig();
|
||||
void updateStatus();
|
||||
void reconnect(QSettings *settings);
|
||||
QList<LCPort> configuration{};
|
||||
|
||||
explicit ShimLCController(QObject *parent = nullptr);
|
||||
~ShimLCController();
|
||||
|
|
@ -221,6 +234,7 @@ public:
|
|||
signals:
|
||||
void newConfigAv();
|
||||
void newStatusAv();
|
||||
void connectionStateChanged(QAbstractSocket::SocketState state);
|
||||
|
||||
private:
|
||||
void parseLcnf(uint32_t idVal);
|
||||
|
|
@ -228,7 +242,6 @@ private:
|
|||
uint32_t ids[2]; // 0 - config / 1 - status
|
||||
ShimLCCommandStack cmd{};
|
||||
QByteArray data{};
|
||||
QList<LCPort> configuration{};
|
||||
LCStatus lastStatus{};
|
||||
};
|
||||
|
||||
|
|
|
|||
29
systemconfiguration.cpp
Normal file
29
systemconfiguration.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include "systemconfiguration.h"
|
||||
#include "ui_systemconfiguration.h"
|
||||
|
||||
SystemConfiguration::SystemConfiguration(ShimLCController* cmd, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::SystemConfiguration)
|
||||
, cmd(cmd)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->configOverView->setModel(&config_view_model);
|
||||
connect(cmd, &ShimLCController::newConfigAv, this, &SystemConfiguration::updateTable);
|
||||
cmd->updateConfig();
|
||||
}
|
||||
|
||||
SystemConfiguration::~SystemConfiguration()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SystemConfiguration::updateTable()
|
||||
{
|
||||
qDebug("Hi");
|
||||
for(int i = 0; i<12; i++)
|
||||
{
|
||||
config_view_model.tableData[i][0] = cmd->configuration.at(i).name;
|
||||
config_view_model.tableData[i][1] = cmd->configuration.at(i).version;
|
||||
config_view_model.tableData[i][2] = cmd->configuration.at(i).serial;
|
||||
}
|
||||
}
|
||||
101
systemconfiguration.h
Normal file
101
systemconfiguration.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#ifndef SYSTEMCONFIGURATION_H
|
||||
#define SYSTEMCONFIGURATION_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTableView>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
#include "shimlccontroller.h"
|
||||
|
||||
class ConfigViewModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QList<QList<QString>> tableData;
|
||||
ConfigViewModel(QObject *parent = nullptr)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
// Initialize the data
|
||||
for (int row = 0; row < 12; ++row) {
|
||||
QList<QString> rowData;
|
||||
for (int col = 0; col < 3; ++col) {
|
||||
rowData.append(QString("Loading..."));
|
||||
}
|
||||
tableData.append(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 12; // Fixed 12 rows
|
||||
}
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 3; // Fixed 4 columns
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
return tableData[index.row()][index.column()];
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (orientation == Qt::Horizontal) {
|
||||
if(section == 0)
|
||||
return QString("Name");
|
||||
if(section == 1)
|
||||
return QString("Version");
|
||||
if(section == 2)
|
||||
return QString("Serial");
|
||||
} else if (orientation == Qt::Vertical) {
|
||||
return QString("Port %1").arg(section + 1);
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class SystemConfiguration;
|
||||
}
|
||||
|
||||
class SystemConfiguration : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SystemConfiguration(ShimLCController* cmd, QWidget *parent);
|
||||
~SystemConfiguration();
|
||||
|
||||
private:
|
||||
Ui::SystemConfiguration *ui;
|
||||
ConfigViewModel config_view_model;
|
||||
ShimLCController* cmd;
|
||||
|
||||
private slots:
|
||||
void updateTable();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // SYSTEMCONFIGURATION_H
|
||||
98
systemconfiguration.ui
Normal file
98
systemconfiguration.ui
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SystemConfiguration</class>
|
||||
<widget class="QDialog" name="SystemConfiguration">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Detected Devices</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="configOverView"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>38</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SystemConfiguration</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>40</x>
|
||||
<y>655</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SystemConfiguration</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>66</x>
|
||||
<y>655</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
Loading…
Add table
Add a link
Reference in a new issue