WIP: attribute support
Dieser Commit ist enthalten in:
Ursprung
33f4db0d4b
Commit
af084bff45
@ -36,6 +36,7 @@
|
|||||||
#include "network/object.hpp"
|
#include "network/object.hpp"
|
||||||
#include "network/property.hpp"
|
#include "network/property.hpp"
|
||||||
#include "subwindow/hardwarelistsubwindow.hpp"
|
#include "subwindow/hardwarelistsubwindow.hpp"
|
||||||
|
#include "subwindow/objecteditsubwindow.hpp"
|
||||||
#include "subwindow/serversettingssubwindow.hpp"
|
#include "subwindow/serversettingssubwindow.hpp"
|
||||||
#include "subwindow/serverconsolesubwindow.hpp"
|
#include "subwindow/serverconsolesubwindow.hpp"
|
||||||
|
|
||||||
@ -47,6 +48,8 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
m_mdiArea{new QMdiArea()}
|
m_mdiArea{new QMdiArea()}
|
||||||
{
|
{
|
||||||
|
instance = this;
|
||||||
|
|
||||||
setWindowTitle("Traintastic");
|
setWindowTitle("Traintastic");
|
||||||
|
|
||||||
QAction* actFullScreen;
|
QAction* actFullScreen;
|
||||||
@ -207,6 +210,21 @@ void MainWindow::toggleFullScreen()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showObjectEdit(const QString& id)
|
||||||
|
{
|
||||||
|
if(!m_mdiSubWindow.objectEdit.contains(id))
|
||||||
|
{
|
||||||
|
ObjectEditSubWindow* window = new ObjectEditSubWindow(id);
|
||||||
|
m_mdiArea->addSubWindow(window);
|
||||||
|
window->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
connect(window, &QMdiSubWindow::destroyed, [this, id](QObject*){ m_mdiSubWindow.objectEdit.remove(id); });
|
||||||
|
window->show();
|
||||||
|
m_mdiSubWindow.objectEdit[id] = window;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_mdiArea->setActiveSubWindow(m_mdiSubWindow.objectEdit[id]);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::showHardware()
|
void MainWindow::showHardware()
|
||||||
{
|
{
|
||||||
if(!m_mdiSubWindow.hardwareList)
|
if(!m_mdiSubWindow.hardwareList)
|
||||||
|
|||||||
@ -25,10 +25,12 @@
|
|||||||
#define MAINWINDOW_HPP
|
#define MAINWINDOW_HPP
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QMap>
|
||||||
#include <enum/traintasticmode.hpp>
|
#include <enum/traintasticmode.hpp>
|
||||||
|
|
||||||
class QMdiArea;
|
class QMdiArea;
|
||||||
class QActionGroup;
|
class QActionGroup;
|
||||||
|
class ObjectEditSubWindow;
|
||||||
class HardwareListSubWindow;
|
class HardwareListSubWindow;
|
||||||
class ServerSettingsSubWindow;
|
class ServerSettingsSubWindow;
|
||||||
class ServerConsoleSubWindow;
|
class ServerConsoleSubWindow;
|
||||||
@ -41,6 +43,7 @@ class MainWindow : public QMainWindow
|
|||||||
QMdiArea* m_mdiArea;
|
QMdiArea* m_mdiArea;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
QMap<QString, ObjectEditSubWindow*> objectEdit;
|
||||||
HardwareListSubWindow* hardwareList = nullptr;
|
HardwareListSubWindow* hardwareList = nullptr;
|
||||||
ServerSettingsSubWindow* serverSettings = nullptr;
|
ServerSettingsSubWindow* serverSettings = nullptr;
|
||||||
ServerConsoleSubWindow* serverConsole = nullptr;
|
ServerConsoleSubWindow* serverConsole = nullptr;
|
||||||
@ -73,6 +76,7 @@ class MainWindow : public QMainWindow
|
|||||||
void exportWorld();
|
void exportWorld();
|
||||||
void toggleFullScreen();
|
void toggleFullScreen();
|
||||||
void showHardware();
|
void showHardware();
|
||||||
|
|
||||||
void showServerSettings();
|
void showServerSettings();
|
||||||
void showServerConsole();
|
void showServerConsole();
|
||||||
void showAbout();
|
void showAbout();
|
||||||
@ -80,11 +84,14 @@ class MainWindow : public QMainWindow
|
|||||||
void updateModeActions();
|
void updateModeActions();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
inline static MainWindow* instance = nullptr;
|
||||||
|
|
||||||
MainWindow(QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void connectToServer();
|
void connectToServer();
|
||||||
|
void showObjectEdit(const QString& id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
#define CLIENT_NETWORK_ABSTRACTPROPERTY_HPP
|
#define CLIENT_NETWORK_ABSTRACTPROPERTY_HPP
|
||||||
|
|
||||||
#include "interfaceitem.hpp"
|
#include "interfaceitem.hpp"
|
||||||
#include <enum/propertytype.hpp>
|
#include <enum/valuetype.hpp>
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
@ -33,16 +33,16 @@ class AbstractProperty : public InterfaceItem
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const PropertyType m_type;
|
const ValueType m_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AbstractProperty(Object& object, const QString& name, PropertyType type) :
|
explicit AbstractProperty(Object& object, const QString& name, ValueType type) :
|
||||||
InterfaceItem(object, name),
|
InterfaceItem(object, name),
|
||||||
m_type{type}
|
m_type{type}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyType type() const { return m_type; }
|
ValueType type() const { return m_type; }
|
||||||
|
|
||||||
virtual const QString& enumName() const = 0;
|
virtual const QString& enumName() const = 0;
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
#include "tablemodel.hpp"
|
#include "tablemodel.hpp"
|
||||||
#include <enum/interfaceitemtype.hpp>
|
#include <enum/interfaceitemtype.hpp>
|
||||||
#include <enum/propertytype.hpp>
|
#include <enum/valuetype.hpp>
|
||||||
|
|
||||||
Client* Client::instance = nullptr;
|
Client* Client::instance = nullptr;
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ void Client::setPropertyBool(Property& property, bool value)
|
|||||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||||
event->write(property.name().toLatin1());
|
event->write(property.name().toLatin1());
|
||||||
event->write(PropertyType::Boolean);
|
event->write(ValueType::Boolean);
|
||||||
event->write(value);
|
event->write(value);
|
||||||
send(event);
|
send(event);
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ void Client::setPropertyInt64(Property& property, int64_t value)
|
|||||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||||
event->write(property.name().toLatin1());
|
event->write(property.name().toLatin1());
|
||||||
event->write(PropertyType::Integer);
|
event->write(ValueType::Integer);
|
||||||
event->write(value);
|
event->write(value);
|
||||||
send(event);
|
send(event);
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ void Client::setPropertyDouble(Property& property, double value)
|
|||||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||||
event->write(property.name().toLatin1());
|
event->write(property.name().toLatin1());
|
||||||
event->write(PropertyType::Float);
|
event->write(ValueType::Float);
|
||||||
event->write(value);
|
event->write(value);
|
||||||
send(event);
|
send(event);
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ void Client::setPropertyString(Property& property, const QString& value)
|
|||||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||||
event->write(property.name().toLatin1());
|
event->write(property.name().toLatin1());
|
||||||
event->write(PropertyType::String);
|
event->write(ValueType::String);
|
||||||
event->write(value.toUtf8());
|
event->write(value.toUtf8());
|
||||||
send(event);
|
send(event);
|
||||||
}
|
}
|
||||||
@ -229,52 +229,96 @@ ObjectPtr Client::readObject(const Message& message)
|
|||||||
while(!message.endOfBlock())
|
while(!message.endOfBlock())
|
||||||
{
|
{
|
||||||
message.readBlock(); // item
|
message.readBlock(); // item
|
||||||
|
InterfaceItem* item = nullptr;
|
||||||
const QString name = QString::fromLatin1(message.read<QByteArray>());
|
const QString name = QString::fromLatin1(message.read<QByteArray>());
|
||||||
const InterfaceItemType type = message.read<InterfaceItemType>();
|
const InterfaceItemType type = message.read<InterfaceItemType>();
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case InterfaceItemType::Property:
|
case InterfaceItemType::Property:
|
||||||
{
|
{
|
||||||
const PropertyType propertyType = message.read<PropertyType>();
|
const ValueType type = message.read<ValueType>();
|
||||||
QVariant value;
|
QVariant value;
|
||||||
switch(propertyType)
|
switch(type)
|
||||||
{
|
{
|
||||||
case PropertyType::Boolean:
|
case ValueType::Boolean:
|
||||||
value = message.read<bool>();
|
value = message.read<bool>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Enum:
|
case ValueType::Enum:
|
||||||
case PropertyType::Integer:
|
case ValueType::Integer:
|
||||||
value = message.read<qint64>();
|
value = message.read<qint64>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Float:
|
case ValueType::Float:
|
||||||
value = message.read<double>();
|
value = message.read<double>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::String:
|
case ValueType::String:
|
||||||
value = QString::fromUtf8(message.read<QByteArray>());
|
value = QString::fromUtf8(message.read<QByteArray>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Object:
|
case ValueType::Object:
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Invalid:
|
case ValueType::Invalid:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Q_ASSERT(value.isValid());
|
// Q_ASSERT(value.isValid());
|
||||||
if(Q_LIKELY(value.isValid()))
|
if(Q_LIKELY(value.isValid()))
|
||||||
{
|
{
|
||||||
Property* p = new Property(*obj, name, propertyType, value);
|
Property* p = new Property(*obj, name, type, value);
|
||||||
if(propertyType == PropertyType::Enum)
|
if(type == ValueType::Enum)
|
||||||
p->m_enumName = QString::fromLatin1(message.read<QByteArray>());
|
p->m_enumName = QString::fromLatin1(message.read<QByteArray>());
|
||||||
obj->m_interfaceItems.add(*p);
|
item = p;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Q_LIKELY(item))
|
||||||
|
{
|
||||||
|
message.readBlock(); // attributes
|
||||||
|
while(!message.endOfBlock())
|
||||||
|
{
|
||||||
|
message.readBlock(); // item
|
||||||
|
const AttributeName attributeName = message.read<AttributeName>();
|
||||||
|
QVariant value;
|
||||||
|
switch(message.read<ValueType>())
|
||||||
|
{
|
||||||
|
case ValueType::Boolean:
|
||||||
|
value = message.read<bool>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Enum:
|
||||||
|
case ValueType::Integer:
|
||||||
|
value = message.read<qint64>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Float:
|
||||||
|
value = message.read<double>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::String:
|
||||||
|
value = QString::fromUtf8(message.read<QByteArray>());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Object:
|
||||||
|
case ValueType::Invalid:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Q_LIKELY(value.isValid()))
|
||||||
|
item->m_attributes[attributeName] = value;
|
||||||
|
|
||||||
|
message.readBlockEnd(); // end attribute
|
||||||
|
}
|
||||||
|
message.readBlockEnd(); // end attributes
|
||||||
|
|
||||||
|
obj->m_interfaceItems.add(*item);
|
||||||
|
}
|
||||||
message.readBlockEnd(); // end item
|
message.readBlockEnd(); // end item
|
||||||
}
|
}
|
||||||
message.readBlockEnd(); // end items
|
message.readBlockEnd(); // end items
|
||||||
@ -329,9 +373,9 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
|||||||
{
|
{
|
||||||
if(Property* property = object->getProperty(QString::fromLatin1(message->read<QByteArray>())))
|
if(Property* property = object->getProperty(QString::fromLatin1(message->read<QByteArray>())))
|
||||||
{
|
{
|
||||||
switch(message->read<PropertyType>())
|
switch(message->read<ValueType>())
|
||||||
{
|
{
|
||||||
case PropertyType::Boolean:
|
case ValueType::Boolean:
|
||||||
{
|
{
|
||||||
const bool value = message->read<bool>();
|
const bool value = message->read<bool>();
|
||||||
property->m_value = value;
|
property->m_value = value;
|
||||||
@ -339,8 +383,8 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
|||||||
emit property->valueChangedBool(value);
|
emit property->valueChangedBool(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PropertyType::Integer:
|
case ValueType::Integer:
|
||||||
case PropertyType::Enum:
|
case ValueType::Enum:
|
||||||
{
|
{
|
||||||
const qlonglong value = message->read<qlonglong>();
|
const qlonglong value = message->read<qlonglong>();
|
||||||
property->m_value = value;
|
property->m_value = value;
|
||||||
@ -350,7 +394,7 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
|||||||
emit property->valueChangedInt(static_cast<int>(value));
|
emit property->valueChangedInt(static_cast<int>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PropertyType::Float:
|
case ValueType::Float:
|
||||||
{
|
{
|
||||||
const double value = message->read<double>();
|
const double value = message->read<double>();
|
||||||
property->m_value = value;
|
property->m_value = value;
|
||||||
@ -358,7 +402,7 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
|||||||
emit property->valueChangedDouble(value);
|
emit property->valueChangedDouble(value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PropertyType::String:
|
case ValueType::String:
|
||||||
{
|
{
|
||||||
const QString value = QString::fromUtf8(message->read<QByteArray>());
|
const QString value = QString::fromUtf8(message->read<QByteArray>());
|
||||||
property->m_value = value;
|
property->m_value = value;
|
||||||
@ -371,6 +415,42 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Message::Command::ObjectAttributeChanged:
|
||||||
|
if(Object* object = m_objects.value(message->read<Handle>(), nullptr))
|
||||||
|
{
|
||||||
|
if(Property* property = object->getProperty(QString::fromLatin1(message->read<QByteArray>())))
|
||||||
|
{
|
||||||
|
AttributeName attributeName = message->read<AttributeName>();
|
||||||
|
QVariant value;
|
||||||
|
switch(message->read<ValueType>())
|
||||||
|
{
|
||||||
|
case ValueType::Boolean:
|
||||||
|
value = message->read<bool>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Integer:
|
||||||
|
case ValueType::Enum:
|
||||||
|
value = message->read<qlonglong>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Float:
|
||||||
|
value = message->read<double>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::String:
|
||||||
|
value = QString::fromUtf8(message->read<QByteArray>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Q_LIKELY(value.isValid()))
|
||||||
|
{
|
||||||
|
property->m_attributes[attributeName] = value;
|
||||||
|
emit property->attributeChanged(attributeName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Message::Command::TableModelColumnHeadersChanged:
|
case Message::Command::TableModelColumnHeadersChanged:
|
||||||
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -28,3 +28,18 @@ InterfaceItem::InterfaceItem(Object& object, const QString& name) :
|
|||||||
m_name{name}
|
m_name{name}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant InterfaceItem::getAttribute(AttributeName name, const QVariant& default_) const
|
||||||
|
{
|
||||||
|
return m_attributes.value(name, default_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterfaceItem::getAttributeBool(AttributeName name, bool default_) const
|
||||||
|
{
|
||||||
|
return m_attributes.value(name, default_).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 InterfaceItem::getAttributeInt64(AttributeName name, qint64 default_) const
|
||||||
|
{
|
||||||
|
return m_attributes.value(name, default_).toLongLong();
|
||||||
|
}
|
||||||
|
|||||||
@ -24,6 +24,9 @@
|
|||||||
#define CLIENT_NETWORK_INTERFACEITEM_HPP
|
#define CLIENT_NETWORK_INTERFACEITEM_HPP
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <enum/attributename.hpp>
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
@ -31,14 +34,30 @@ class InterfaceItem : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class Client;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const QString m_name;
|
const QString m_name;
|
||||||
|
QMap<AttributeName, QVariant> m_attributes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InterfaceItem(Object& object, const QString& name);
|
explicit InterfaceItem(Object& object, const QString& name);
|
||||||
|
|
||||||
const QString& name() const { return m_name; }
|
const QString& name() const { return m_name; }
|
||||||
const QString& displayName() const { return m_name; }
|
const QString& displayName() const { return m_name; }
|
||||||
|
|
||||||
|
QVariant getAttribute(AttributeName name, const QVariant& default_) const;
|
||||||
|
bool getAttributeBool(AttributeName name, bool default_) const;
|
||||||
|
qint64 getAttributeInt64(AttributeName name, qint64 default_) const;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T getAttributeEnum(AttributeName name, T default_) const
|
||||||
|
{
|
||||||
|
return static_cast<T>(getAttributeInt64(name, static_cast<qint64>(default_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void attributeChanged(AttributeName name, const QVariant& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
|
||||||
Property::Property(Object& object, const QString& name, PropertyType type, const QVariant& value) :
|
Property::Property(Object& object, const QString& name, ValueType type, const QVariant& value) :
|
||||||
AbstractProperty(object, name, type),
|
AbstractProperty(object, name, type),
|
||||||
m_value{value}
|
m_value{value}
|
||||||
{
|
{
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class Property : public AbstractProperty
|
|||||||
QString m_enumName;
|
QString m_enumName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Property(Object& object, const QString& name, PropertyType type, const QVariant& value);
|
explicit Property(Object& object, const QString& name, ValueType type, const QVariant& value);
|
||||||
|
|
||||||
const QString& enumName() const final { Q_ASSERT(!m_enumName.isEmpty()); return m_enumName; }
|
const QString& enumName() const final { Q_ASSERT(!m_enumName.isEmpty()); return m_enumName; }
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ HardwareListSubWindow::HardwareListSubWindow(QWidget* parent) :
|
|||||||
QMdiSubWindow(parent)
|
QMdiSubWindow(parent)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Hardware"));
|
setWindowTitle(tr("Hardware"));
|
||||||
//setWindowIcon(QIcon(":/dark/hardware.svg"));
|
setWindowIcon(QIcon(":/dark/hardware.svg"));
|
||||||
setWidget(new HardwareWidget(this));
|
setWidget(new HardwareWidget(this));
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|||||||
9
client/src/subwindow/objecteditsubwindow.cpp
Normale Datei
9
client/src/subwindow/objecteditsubwindow.cpp
Normale Datei
@ -0,0 +1,9 @@
|
|||||||
|
#include "objecteditsubwindow.hpp"
|
||||||
|
#include "../widget/objecteditwidget.hpp"
|
||||||
|
|
||||||
|
ObjectEditSubWindow::ObjectEditSubWindow(const QString& id, QWidget* parent) :
|
||||||
|
QMdiSubWindow(parent)
|
||||||
|
{
|
||||||
|
setWindowTitle(id);
|
||||||
|
setWidget(new ObjectEditWidget(id, this));
|
||||||
|
}
|
||||||
12
client/src/subwindow/objecteditsubwindow.hpp
Normale Datei
12
client/src/subwindow/objecteditsubwindow.hpp
Normale Datei
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef OBJECTEDITSUBWINDOW_HPP
|
||||||
|
#define OBJECTEDITSUBWINDOW_HPP
|
||||||
|
|
||||||
|
#include <QMdiSubWindow>
|
||||||
|
|
||||||
|
class ObjectEditSubWindow : public QMdiSubWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectEditSubWindow(const QString& id, QWidget* parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -35,9 +35,25 @@
|
|||||||
#include "../widget/propertylineedit.hpp"
|
#include "../widget/propertylineedit.hpp"
|
||||||
#include "../widget/propertytextedit.hpp"
|
#include "../widget/propertytextedit.hpp"
|
||||||
#include "../widget/propertydirectioncontrol.hpp"
|
#include "../widget/propertydirectioncontrol.hpp"
|
||||||
|
#include <enum/category.hpp>
|
||||||
|
|
||||||
#include <enum/direction.hpp>
|
#include <enum/direction.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
QString toString(Category value)
|
||||||
|
{
|
||||||
|
switch(value)
|
||||||
|
{
|
||||||
|
case Category::General: return "General";
|
||||||
|
case Category::Info: return "Info";
|
||||||
|
case Category::Notes: return "Notes";
|
||||||
|
case Category::Status: return "Status";
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ObjectEditWidget::ObjectEditWidget(const QString& id, QWidget* parent) :
|
ObjectEditWidget::ObjectEditWidget(const QString& id, QWidget* parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
m_id{id}
|
m_id{id}
|
||||||
@ -67,31 +83,34 @@ ObjectEditWidget::~ObjectEditWidget()
|
|||||||
|
|
||||||
void ObjectEditWidget::buildForm()
|
void ObjectEditWidget::buildForm()
|
||||||
{
|
{
|
||||||
QMap<QString, QWidget*> tabs;
|
QMap<Category, QWidget*> tabs;
|
||||||
|
QList<Category> tabOrder;
|
||||||
|
|
||||||
for(const QString& name : m_object->interfaceItems().names())
|
for(const QString& name : m_object->interfaceItems().names())
|
||||||
if(Property* property = m_object->getProperty(name))
|
if(Property* property = m_object->getProperty(name))
|
||||||
{
|
{
|
||||||
|
Category category = property->getAttributeEnum<Category>(AttributeName::Category, Category::General);
|
||||||
QWidget* w = nullptr;
|
QWidget* w = nullptr;
|
||||||
|
|
||||||
if(property->type() == PropertyType::Boolean)
|
if(property->type() == ValueType::Boolean)
|
||||||
w = new PropertyCheckBox(*property);
|
w = new PropertyCheckBox(*property);
|
||||||
else if(property->type() == PropertyType::Integer)
|
else if(property->type() == ValueType::Integer)
|
||||||
w = new PropertySpinBox(*property);
|
w = new PropertySpinBox(*property);
|
||||||
else if(property->type() == PropertyType::String)
|
else if(property->type() == ValueType::String)
|
||||||
{
|
{
|
||||||
if(property->name() == "notes")
|
if(category == Category::Notes && property->name() == "notes")
|
||||||
{
|
{
|
||||||
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
||||||
edit->setPlaceholderText(property->displayName());
|
edit->setPlaceholderText(property->displayName());
|
||||||
Q_ASSERT(!tabs.contains("notes"));
|
Q_ASSERT(!tabs.contains(category));
|
||||||
tabs.insert("notes", edit);
|
tabs.insert(category, edit);
|
||||||
|
tabOrder.append(category);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
w = new PropertyLineEdit(*property);
|
w = new PropertyLineEdit(*property);
|
||||||
}
|
}
|
||||||
else if(property->type() == PropertyType::Enum)
|
else if(property->type() == ValueType::Enum)
|
||||||
{
|
{
|
||||||
if(property->enumName() == EnumName<Direction>::value)
|
if(property->enumName() == EnumName<Direction>::value)
|
||||||
{
|
{
|
||||||
@ -103,15 +122,15 @@ void ObjectEditWidget::buildForm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWidget* tabWidget;
|
QWidget* tabWidget;
|
||||||
QString tab = "general"; // TODO: get sttribute
|
if(!tabs.contains(category))
|
||||||
if(!tabs.contains(tab))
|
|
||||||
{
|
{
|
||||||
tabWidget = new QWidget();
|
tabWidget = new QWidget();
|
||||||
tabWidget->setLayout(new QFormLayout());
|
tabWidget->setLayout(new QFormLayout());
|
||||||
tabs.insert(tab, tabWidget);
|
tabs.insert(category, tabWidget);
|
||||||
|
tabOrder.append(category);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tabWidget = tabs[tab];
|
tabWidget = tabs[category];
|
||||||
|
|
||||||
static_cast<QFormLayout*>(tabWidget->layout())->addRow(property->displayName(), w);
|
static_cast<QFormLayout*>(tabWidget->layout())->addRow(property->displayName(), w);
|
||||||
}
|
}
|
||||||
@ -119,8 +138,8 @@ void ObjectEditWidget::buildForm()
|
|||||||
if(tabs.count() > 1)
|
if(tabs.count() > 1)
|
||||||
{
|
{
|
||||||
QTabWidget* tabWidget = new QTabWidget();
|
QTabWidget* tabWidget = new QTabWidget();
|
||||||
for(auto it = tabs.constBegin(); it != tabs.constEnd(); it++)
|
for(Category category : tabOrder)
|
||||||
tabWidget->addTab(it.value(), it.key());
|
tabWidget->addTab(tabs.value(category), toString(category));
|
||||||
QVBoxLayout* l = new QVBoxLayout();
|
QVBoxLayout* l = new QVBoxLayout();
|
||||||
l->setMargin(0);
|
l->setMargin(0);
|
||||||
l->addWidget(tabWidget);
|
l->addWidget(tabWidget);
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
#include "../widget/alertwidget.hpp"
|
#include "../widget/alertwidget.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include "objecteditwidget.hpp"
|
#include "../mainwindow.hpp"
|
||||||
|
|
||||||
ObjectListWidget::ObjectListWidget(const QString& id, QWidget* parent) :
|
ObjectListWidget::ObjectListWidget(const QString& id, QWidget* parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
@ -111,7 +111,7 @@ void ObjectListWidget::tableDoubleClicked(const QModelIndex& index)
|
|||||||
{
|
{
|
||||||
const QString id = m_tableWidget->getRowObjectId(index.row());
|
const QString id = m_tableWidget->getRowObjectId(index.row());
|
||||||
if(!id.isEmpty())
|
if(!id.isEmpty())
|
||||||
(new ObjectEditWidget(id))->show();
|
MainWindow::instance->showObjectEdit(id);//emit rowDoubleClicked(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,9 @@ class ObjectListWidget : public QWidget
|
|||||||
public:
|
public:
|
||||||
explicit ObjectListWidget(const QString& id, QWidget* parent = nullptr);
|
explicit ObjectListWidget(const QString& id, QWidget* parent = nullptr);
|
||||||
~ObjectListWidget() override;
|
~ObjectListWidget() override;
|
||||||
|
|
||||||
|
//signals:
|
||||||
|
// void rowDoubleClicked(const QString& id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -23,12 +23,62 @@
|
|||||||
#include "propertycheckbox.hpp"
|
#include "propertycheckbox.hpp"
|
||||||
#include "../network/property.hpp"
|
#include "../network/property.hpp"
|
||||||
|
|
||||||
|
class InternalUpdateHolder
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool& m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline InternalUpdateHolder(bool& value) :
|
||||||
|
m_value{value}
|
||||||
|
{
|
||||||
|
Q_ASSERT(!m_value);
|
||||||
|
m_value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~InternalUpdateHolder()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_value);
|
||||||
|
m_value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
PropertyCheckBox::PropertyCheckBox(Property& property, QWidget* parent) :
|
PropertyCheckBox::PropertyCheckBox(Property& property, QWidget* parent) :
|
||||||
QCheckBox(parent),
|
QCheckBox(parent),
|
||||||
m_property{property}
|
m_property{property},
|
||||||
|
m_internalUpdate{false}
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_property.type() == PropertyType::Boolean);
|
Q_ASSERT(m_property.type() == ValueType::Boolean);
|
||||||
|
setEnabled(m_property.getAttributeBool(AttributeName::Enabled, true));
|
||||||
|
setVisible(m_property.getAttributeBool(AttributeName::Visible, true));
|
||||||
setChecked(m_property.toBool());
|
setChecked(m_property.toBool());
|
||||||
connect(&m_property, &Property::valueChangedBool, this, &PropertyCheckBox::setChecked);
|
connect(&m_property, &Property::valueChangedBool,
|
||||||
connect(this, &PropertyCheckBox::toggled, &m_property, &Property::setValueBool);
|
[this](bool value)
|
||||||
|
{
|
||||||
|
InternalUpdateHolder hold(m_internalUpdate);
|
||||||
|
setChecked(value);
|
||||||
|
});
|
||||||
|
connect(&m_property, &Property::attributeChanged,
|
||||||
|
[this](AttributeName name, const QVariant& value)
|
||||||
|
{
|
||||||
|
switch(name)
|
||||||
|
{
|
||||||
|
case AttributeName::Enabled:
|
||||||
|
setEnabled(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AttributeName::Visible:
|
||||||
|
setVisible(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(this, &PropertyCheckBox::toggled,
|
||||||
|
[this](bool value)
|
||||||
|
{
|
||||||
|
if(!m_internalUpdate)
|
||||||
|
m_property.setValueBool(value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class PropertyCheckBox : public QCheckBox
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
Property& m_property;
|
Property& m_property;
|
||||||
|
bool m_internalUpdate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PropertyCheckBox(Property& property, QWidget* parent = nullptr);
|
PropertyCheckBox(Property& property, QWidget* parent = nullptr);
|
||||||
|
|||||||
@ -34,21 +34,36 @@ PropertyDirectionControl::PropertyDirectionControl(Property& property, QWidget*
|
|||||||
{
|
{
|
||||||
Q_ASSERT(property.enumName() == EnumName<Direction>::value);
|
Q_ASSERT(property.enumName() == EnumName<Direction>::value);
|
||||||
|
|
||||||
QHBoxLayout* l = new QHBoxLayout();
|
setEnabled(m_property.getAttributeBool(AttributeName::Enabled, true));
|
||||||
|
setVisible(m_property.getAttributeBool(AttributeName::Visible, true));
|
||||||
|
|
||||||
m_reverse->setArrowType(Qt::LeftArrow);
|
m_reverse->setArrowType(Qt::LeftArrow);
|
||||||
//m_reverse->setCheckable(true);
|
|
||||||
|
|
||||||
m_forward->setArrowType(Qt::RightArrow);
|
m_forward->setArrowType(Qt::RightArrow);
|
||||||
//m_forward->setCheckable(true);
|
|
||||||
|
|
||||||
|
QHBoxLayout* l = new QHBoxLayout();
|
||||||
l->addWidget(m_reverse);
|
l->addWidget(m_reverse);
|
||||||
l->addWidget(m_forward);
|
l->addWidget(m_forward);
|
||||||
|
|
||||||
setLayout(l);
|
setLayout(l);
|
||||||
|
|
||||||
setValue(m_property.toInt64());
|
setValue(m_property.toInt64());
|
||||||
connect(&m_property, &Property::valueChangedInt64, this, &PropertyDirectionControl::setValue);
|
connect(&m_property, &Property::valueChangedInt64, this, &PropertyDirectionControl::setValue);
|
||||||
|
connect(&m_property, &Property::attributeChanged,
|
||||||
|
[this](AttributeName name, const QVariant& value)
|
||||||
|
{
|
||||||
|
switch(name)
|
||||||
|
{
|
||||||
|
case AttributeName::Enabled:
|
||||||
|
setEnabled(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AttributeName::Visible:
|
||||||
|
setVisible(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
connect(m_reverse, &QToolButton::clicked, this, &PropertyDirectionControl::buttonClicked);
|
connect(m_reverse, &QToolButton::clicked, this, &PropertyDirectionControl::buttonClicked);
|
||||||
connect(m_forward, &QToolButton::clicked, this, &PropertyDirectionControl::buttonClicked);
|
connect(m_forward, &QToolButton::clicked, this, &PropertyDirectionControl::buttonClicked);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,8 +27,27 @@ PropertyLineEdit::PropertyLineEdit(Property& property, QWidget* parent) :
|
|||||||
QLineEdit(parent),
|
QLineEdit(parent),
|
||||||
m_property{property}
|
m_property{property}
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_property.type() == PropertyType::String);
|
Q_ASSERT(m_property.type() == ValueType::String);
|
||||||
|
setEnabled(m_property.getAttributeBool(AttributeName::Enabled, true));
|
||||||
|
setVisible(m_property.getAttributeBool(AttributeName::Visible, true));
|
||||||
setText(m_property.toString());
|
setText(m_property.toString());
|
||||||
connect(&m_property, &Property::valueChangedString, this, &PropertyLineEdit::setText);
|
connect(&m_property, &Property::valueChangedString, this, &PropertyLineEdit::setText);
|
||||||
|
connect(&m_property, &Property::attributeChanged,
|
||||||
|
[this](AttributeName name, const QVariant& value)
|
||||||
|
{
|
||||||
|
switch(name)
|
||||||
|
{
|
||||||
|
case AttributeName::Enabled:
|
||||||
|
setEnabled(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AttributeName::Visible:
|
||||||
|
setVisible(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
connect(this, &PropertyLineEdit::textEdited, &m_property, &Property::setValueString);
|
connect(this, &PropertyLineEdit::textEdited, &m_property, &Property::setValueString);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,9 +27,28 @@ PropertySpinBox::PropertySpinBox(AbstractProperty& property, QWidget* parent) :
|
|||||||
QSpinBox(parent),
|
QSpinBox(parent),
|
||||||
m_property{property}
|
m_property{property}
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_property.type() == PropertyType::Integer);
|
Q_ASSERT(m_property.type() == ValueType::Integer);
|
||||||
|
setEnabled(m_property.getAttributeBool(AttributeName::Enabled, true));
|
||||||
|
setVisible(m_property.getAttributeBool(AttributeName::Visible, true));
|
||||||
setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
|
setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
|
||||||
setValue(m_property.toInt());
|
setValue(m_property.toInt());
|
||||||
connect(&m_property, &AbstractProperty::valueChangedInt, this, &PropertySpinBox::setValue);
|
connect(&m_property, &AbstractProperty::valueChangedInt, this, &PropertySpinBox::setValue);
|
||||||
|
connect(&m_property, &AbstractProperty::attributeChanged,
|
||||||
|
[this](AttributeName name, const QVariant& value)
|
||||||
|
{
|
||||||
|
switch(name)
|
||||||
|
{
|
||||||
|
case AttributeName::Enabled:
|
||||||
|
setEnabled(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AttributeName::Visible:
|
||||||
|
setVisible(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
connect(this, QOverload<int>::of(&PropertySpinBox::valueChanged), &m_property, &AbstractProperty::setValueInt);
|
connect(this, QOverload<int>::of(&PropertySpinBox::valueChanged), &m_property, &AbstractProperty::setValueInt);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,8 +27,25 @@ PropertyTextEdit::PropertyTextEdit(Property& property, QWidget* parent) :
|
|||||||
QTextEdit(parent),
|
QTextEdit(parent),
|
||||||
m_property{property}
|
m_property{property}
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_property.type() == PropertyType::String);
|
Q_ASSERT(m_property.type() == ValueType::String);
|
||||||
setPlainText(m_property.toString());
|
setPlainText(m_property.toString());
|
||||||
connect(&m_property, &Property::valueChangedString, this, &PropertyTextEdit::setPlainText);
|
connect(&m_property, &Property::valueChangedString, this, &PropertyTextEdit::setPlainText);
|
||||||
|
connect(&m_property, &Property::attributeChanged,
|
||||||
|
[this](AttributeName name, const QVariant& value)
|
||||||
|
{
|
||||||
|
switch(name)
|
||||||
|
{
|
||||||
|
case AttributeName::Enabled:
|
||||||
|
setEnabled(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AttributeName::Visible:
|
||||||
|
setVisible(value.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
connect(this, &PropertyTextEdit::textChanged, [this](){ m_property.setValueString(toPlainText()); });
|
connect(this, &PropertyTextEdit::textChanged, [this](){ m_property.setValueString(toPlainText()); });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,8 @@ SOURCES += \
|
|||||||
src/widget/propertylineedit.cpp \
|
src/widget/propertylineedit.cpp \
|
||||||
src/widget/propertyspinbox.cpp \
|
src/widget/propertyspinbox.cpp \
|
||||||
src/widget/propertydirectioncontrol.cpp \
|
src/widget/propertydirectioncontrol.cpp \
|
||||||
src/widget/propertytextedit.cpp
|
src/widget/propertytextedit.cpp \
|
||||||
|
src/subwindow/objecteditsubwindow.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/mainwindow.hpp \
|
src/mainwindow.hpp \
|
||||||
@ -77,7 +78,8 @@ HEADERS += \
|
|||||||
src/widget/propertylineedit.hpp \
|
src/widget/propertylineedit.hpp \
|
||||||
src/widget/propertyspinbox.hpp \
|
src/widget/propertyspinbox.hpp \
|
||||||
src/widget/propertydirectioncontrol.hpp \
|
src/widget/propertydirectioncontrol.hpp \
|
||||||
src/widget/propertytextedit.hpp
|
src/widget/propertytextedit.hpp \
|
||||||
|
src/subwindow/objecteditsubwindow.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
dark.qrc
|
dark.qrc
|
||||||
|
|||||||
15
server/src/core/abstractattribute.cpp
Normale Datei
15
server/src/core/abstractattribute.cpp
Normale Datei
@ -0,0 +1,15 @@
|
|||||||
|
#include "abstractattribute.hpp"
|
||||||
|
#include "interfaceitem.hpp"
|
||||||
|
#include "object.hpp"
|
||||||
|
|
||||||
|
AbstractAttribute::AbstractAttribute(InterfaceItem& item, AttributeName name, ValueType type) :
|
||||||
|
m_item{item},
|
||||||
|
m_name{name},
|
||||||
|
m_type{type}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractAttribute::changed()
|
||||||
|
{
|
||||||
|
m_item.object().attributeChanged(*this);
|
||||||
|
}
|
||||||
32
server/src/core/abstractattribute.hpp
Normale Datei
32
server/src/core/abstractattribute.hpp
Normale Datei
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef ABSTRACTATTRIBUTE_HPP
|
||||||
|
#define ABSTRACTATTRIBUTE_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <enum/attributename.hpp>
|
||||||
|
#include <enum/valuetype.hpp>
|
||||||
|
|
||||||
|
class InterfaceItem;
|
||||||
|
|
||||||
|
class AbstractAttribute
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
InterfaceItem& m_item;
|
||||||
|
const AttributeName m_name;
|
||||||
|
const ValueType m_type;
|
||||||
|
|
||||||
|
void changed();
|
||||||
|
|
||||||
|
public:
|
||||||
|
AbstractAttribute(InterfaceItem& item, AttributeName name, ValueType type);
|
||||||
|
|
||||||
|
inline InterfaceItem& item() const { return m_item; }
|
||||||
|
inline AttributeName name() const { return m_name; }
|
||||||
|
inline ValueType type() const { return m_type; }
|
||||||
|
|
||||||
|
virtual bool toBool() const = 0;
|
||||||
|
virtual int64_t toInt64() const = 0;
|
||||||
|
virtual double toDouble() const = 0;
|
||||||
|
virtual std::string toString() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -29,5 +29,5 @@ void AbstractProperty::changed()
|
|||||||
{
|
{
|
||||||
std::cout << "AbstractProperty::changed" << std::endl;
|
std::cout << "AbstractProperty::changed" << std::endl;
|
||||||
|
|
||||||
m_object.propertyChanged(m_object, *this);
|
m_object.propertyChanged(*this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
#define SERVER_CORE_ABSTRACTPROPERTY_HPP
|
#define SERVER_CORE_ABSTRACTPROPERTY_HPP
|
||||||
|
|
||||||
#include "interfaceitem.hpp"
|
#include "interfaceitem.hpp"
|
||||||
#include <enum/propertytype.hpp>
|
#include <enum/valuetype.hpp>
|
||||||
#include "propertyflags.hpp"
|
#include "propertyflags.hpp"
|
||||||
#include "objectptr.hpp"
|
#include "objectptr.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -33,18 +33,18 @@
|
|||||||
class AbstractProperty : public InterfaceItem
|
class AbstractProperty : public InterfaceItem
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const PropertyType m_type;
|
const ValueType m_type;
|
||||||
PropertyFlags m_flags;
|
PropertyFlags m_flags;
|
||||||
|
|
||||||
void changed();
|
void changed();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbstractProperty(Object& object, const std::string& name, PropertyType type, PropertyFlags flags) :
|
AbstractProperty(Object& object, const std::string& name, ValueType type, PropertyFlags flags) :
|
||||||
InterfaceItem{object, name},
|
InterfaceItem{object, name},
|
||||||
m_type{type},
|
m_type{type},
|
||||||
m_flags{flags}
|
m_flags{flags}
|
||||||
{
|
{
|
||||||
assert(type != PropertyType::Invalid);
|
assert(type != ValueType::Invalid);
|
||||||
assert(is_access_valid(flags) && is_store_valid(flags));
|
assert(is_access_valid(flags) && is_store_valid(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ class AbstractProperty : public InterfaceItem
|
|||||||
return true;//!is_empty(m_flags & PropertyFlags::WriteOnly);
|
return true;//!is_empty(m_flags & PropertyFlags::WriteOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyType type() const
|
ValueType type() const
|
||||||
{
|
{
|
||||||
return m_type;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|||||||
51
server/src/core/attribute.hpp
Normale Datei
51
server/src/core/attribute.hpp
Normale Datei
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef INTERFACEITEMATTRIBUTE_HPP
|
||||||
|
#define INTERFACEITEMATTRIBUTE_HPP
|
||||||
|
|
||||||
|
#include "abstractattribute.hpp"
|
||||||
|
#include "to.hpp"
|
||||||
|
#include "valuetypetraits.hpp"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Attribute : public AbstractAttribute
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
T m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Attribute(InterfaceItem& item, AttributeName name, const T& value) :
|
||||||
|
AbstractAttribute{item, name, value_type_v<T>},
|
||||||
|
m_value{value}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool toBool() const final
|
||||||
|
{
|
||||||
|
return to<bool>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t toInt64() const final
|
||||||
|
{
|
||||||
|
return to<int64_t>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
double toDouble() const final
|
||||||
|
{
|
||||||
|
return to<double>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const final
|
||||||
|
{
|
||||||
|
return to<std::string>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(const T& value)
|
||||||
|
{
|
||||||
|
if(m_value != value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -36,7 +36,8 @@ IdObject::IdObject(const std::weak_ptr<World> world, const std::string& _id) :
|
|||||||
return true;
|
return true;
|
||||||
}}
|
}}
|
||||||
{
|
{
|
||||||
m_interfaceItems.add(id);
|
m_interfaceItems.add(id)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdObject::~IdObject()
|
IdObject::~IdObject()
|
||||||
@ -50,3 +51,8 @@ void IdObject::addToWorld()
|
|||||||
if(auto world = m_world.lock())
|
if(auto world = m_world.lock())
|
||||||
world->m_objects.emplace(id, weak_from_this());
|
world->m_objects.emplace(id, weak_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IdObject::modeChanged(TraintasticMode mode)
|
||||||
|
{
|
||||||
|
id.setAttributeEnabled(mode == TraintasticMode::Edit);
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "property.hpp"
|
#include "property.hpp"
|
||||||
|
#include <enum/traintasticmode.hpp>
|
||||||
|
|
||||||
#define CREATE(T) \
|
#define CREATE(T) \
|
||||||
static std::shared_ptr<T> create(const std::weak_ptr<World>& world, const std::string& _id) \
|
static std::shared_ptr<T> create(const std::weak_ptr<World>& world, const std::string& _id) \
|
||||||
@ -43,6 +44,7 @@ class IdObject : public Object
|
|||||||
|
|
||||||
IdObject(const std::weak_ptr<World> world, const std::string& _id);
|
IdObject(const std::weak_ptr<World> world, const std::string& _id);
|
||||||
void addToWorld();
|
void addToWorld();
|
||||||
|
void modeChanged(TraintasticMode mode) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Property<std::string> id;
|
Property<std::string> id;
|
||||||
|
|||||||
@ -23,15 +23,36 @@
|
|||||||
#ifndef SERVER_CORE_INTERFACEITEM_HPP
|
#ifndef SERVER_CORE_INTERFACEITEM_HPP
|
||||||
#define SERVER_CORE_INTERFACEITEM_HPP
|
#define SERVER_CORE_INTERFACEITEM_HPP
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "attribute.hpp"
|
||||||
|
#include <enum/category.hpp>
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
class InterfaceItem
|
class InterfaceItem
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using Attributes = std::unordered_map<AttributeName, std::unique_ptr<AbstractAttribute>>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Object& m_object;
|
Object& m_object;
|
||||||
const std::string m_name;
|
const std::string m_name;
|
||||||
|
Attributes m_attributes;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
InterfaceItem& addAttribute(AttributeName name, const T& value)
|
||||||
|
{
|
||||||
|
m_attributes.emplace(name, std::make_unique<Attribute<T>>(*this, name, value));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void setAttribute(AttributeName name, const T& value)
|
||||||
|
{
|
||||||
|
static_cast<Attribute<T>*>(m_attributes[name].get())->setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InterfaceItem(Object& object, const std::string& name) :
|
InterfaceItem(Object& object, const std::string& name) :
|
||||||
@ -53,6 +74,17 @@ class InterfaceItem
|
|||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Attributes& attributes() const
|
||||||
|
{
|
||||||
|
return m_attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline InterfaceItem& addAttributeCategory(Category value) { return addAttribute(AttributeName::Category, value); }
|
||||||
|
inline InterfaceItem& addAttributeEnabled(bool value) { return addAttribute(AttributeName::Enabled, value); }
|
||||||
|
inline InterfaceItem& addAttributeVisible(bool value) { return addAttribute(AttributeName::Visible, value); }
|
||||||
|
|
||||||
|
inline void setAttributeEnabled(bool value) { setAttribute(AttributeName::Enabled, value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "interfaceitems.hpp"
|
#include "interfaceitems.hpp"
|
||||||
#include "interfaceitem.hpp"
|
#include "interfaceitem.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
InterfaceItem* InterfaceItems::find(const std::string& name) const
|
InterfaceItem* InterfaceItems::find(const std::string& name) const
|
||||||
{
|
{
|
||||||
@ -29,8 +30,16 @@ InterfaceItem* InterfaceItems::find(const std::string& name) const
|
|||||||
return (it != m_items.end()) ? &it->second : nullptr;
|
return (it != m_items.end()) ? &it->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceItems::add(InterfaceItem& item)
|
InterfaceItem& InterfaceItems::add(InterfaceItem& item)
|
||||||
{
|
{
|
||||||
m_items.emplace(item.name(), item);
|
m_items.emplace(item.name(), item);
|
||||||
m_itemOrder.push_back(item.name());
|
m_itemOrder.push_back(item.name());
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
InterfaceItem& InterfaceItems::insertBefore(InterfaceItem& item, const InterfaceItem& before)
|
||||||
|
{
|
||||||
|
m_items.emplace(item.name(), item);
|
||||||
|
m_itemOrder.insert(std::find(m_itemOrder.begin(), m_itemOrder.end(), before.name()), item.name());
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,9 @@ class InterfaceItems
|
|||||||
const std::list<std::string>& names() const { return m_itemOrder; }
|
const std::list<std::string>& names() const { return m_itemOrder; }
|
||||||
|
|
||||||
InterfaceItem* find(const std::string& name) const;
|
InterfaceItem* find(const std::string& name) const;
|
||||||
void add(InterfaceItem& item);
|
|
||||||
|
InterfaceItem& add(InterfaceItem& item);
|
||||||
|
InterfaceItem& insertBefore(InterfaceItem& item, const InterfaceItem& before);
|
||||||
|
|
||||||
inline InterfaceItem& operator[](const std::string& name) const { return m_items.at(name); }
|
inline InterfaceItem& operator[](const std::string& name) const { return m_items.at(name); }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
#include "objectptr.hpp"
|
#include "objectptr.hpp"
|
||||||
#include <boost/signals2/signal.hpp>
|
#include <boost/signals2/signal.hpp>
|
||||||
#include "interfaceitems.hpp"
|
#include "interfaceitems.hpp"
|
||||||
|
#include <enum/traintasticmode.hpp>
|
||||||
|
|
||||||
#define CLASS_ID(id) \
|
#define CLASS_ID(id) \
|
||||||
public: \
|
public: \
|
||||||
@ -34,17 +35,23 @@
|
|||||||
|
|
||||||
class AbstractMethod;
|
class AbstractMethod;
|
||||||
class AbstractProperty;
|
class AbstractProperty;
|
||||||
|
class AbstractAttribute;
|
||||||
|
|
||||||
class Object : public std::enable_shared_from_this<Object>
|
class Object : public std::enable_shared_from_this<Object>
|
||||||
{
|
{
|
||||||
|
friend class World;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InterfaceItems m_interfaceItems;
|
InterfaceItems m_interfaceItems;
|
||||||
|
|
||||||
//void log(LogLevel level, const std::string& message) const;
|
//void log(LogLevel level, const std::string& message) const;
|
||||||
//inline void logError(const std::string& message) const { log(LogLevel::Error, message); }
|
//inline void logError(const std::string& message) const { log(LogLevel::Error, message); }
|
||||||
|
|
||||||
|
virtual void modeChanged(TraintasticMode) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
boost::signals2::signal<void (Object& object, AbstractProperty&)> propertyChanged;
|
boost::signals2::signal<void (AbstractProperty&)> propertyChanged;
|
||||||
|
boost::signals2::signal<void (AbstractAttribute&)> attributeChanged;
|
||||||
|
|
||||||
Object();
|
Object();
|
||||||
virtual ~Object();
|
virtual ~Object();
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class ObjectProperty : public AbstractProperty
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ObjectProperty(Object* object, const std::string& name, const std::shared_ptr<T>& value, PropertyFlags flags) :
|
ObjectProperty(Object* object, const std::string& name, const std::shared_ptr<T>& value, PropertyFlags flags) :
|
||||||
AbstractProperty(*object, name, PropertyType::Object, flags),
|
AbstractProperty(*object, name, ValueType::Object, flags),
|
||||||
m_value{value}
|
m_value{value}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
#define SERVER_CORE_PROPERTY_HPP
|
#define SERVER_CORE_PROPERTY_HPP
|
||||||
|
|
||||||
#include "abstractproperty.hpp"
|
#include "abstractproperty.hpp"
|
||||||
#include "propertytypetraits.hpp"
|
#include "valuetypetraits.hpp"
|
||||||
#include "to.hpp"
|
#include "to.hpp"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <enum/enum.hpp>
|
#include <enum/enum.hpp>
|
||||||
@ -43,7 +43,7 @@ class Property : public AbstractProperty
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Property(Object* object, const std::string& name, const T& value, PropertyFlags flags) :
|
Property(Object* object, const std::string& name, const T& value, PropertyFlags flags) :
|
||||||
AbstractProperty(*object, name, property_type<T>::value, flags),
|
AbstractProperty(*object, name, value_type<T>::value, flags),
|
||||||
m_value{value}
|
m_value{value}
|
||||||
{
|
{
|
||||||
//static_assert(property_type<T>::value != PropertyType::Invalid);
|
//static_assert(property_type<T>::value != PropertyType::Invalid);
|
||||||
@ -90,6 +90,15 @@ class Property : public AbstractProperty
|
|||||||
throw invalid_value_error();
|
throw invalid_value_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setValueInternal(T value)
|
||||||
|
{
|
||||||
|
if(m_value != value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
operator const T&() const
|
operator const T&() const
|
||||||
{
|
{
|
||||||
return m_value;
|
return m_value;
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include "traintastic.hpp"
|
#include "traintastic.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "abstractproperty.hpp"
|
#include "abstractproperty.hpp"
|
||||||
|
#include "abstractattribute.hpp"
|
||||||
#include <enum/interfaceitemtype.hpp>
|
#include <enum/interfaceitemtype.hpp>
|
||||||
#include "tablemodel.hpp"
|
#include "tablemodel.hpp"
|
||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
@ -162,6 +163,8 @@ bool Session::processMessage(const Message& message)
|
|||||||
Handle handle = message.read<Handle>();
|
Handle handle = message.read<Handle>();
|
||||||
Traintastic::instance->console->debug(m_client->m_id, "ReleaseObject: " + std::to_string(handle));
|
Traintastic::instance->console->debug(m_client->m_id, "ReleaseObject: " + std::to_string(handle));
|
||||||
m_handles.removeHandle(handle);
|
m_handles.removeHandle(handle);
|
||||||
|
m_propertyChanged.erase(handle);
|
||||||
|
m_attributeChanged.erase(handle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Message::Command::ObjectSetProperty:
|
case Message::Command::ObjectSetProperty:
|
||||||
@ -172,21 +175,21 @@ bool Session::processMessage(const Message& message)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch(message.read<PropertyType>())
|
switch(message.read<ValueType>())
|
||||||
{
|
{
|
||||||
case PropertyType::Boolean:
|
case ValueType::Boolean:
|
||||||
property->fromBool(message.read<bool>());
|
property->fromBool(message.read<bool>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Integer:
|
case ValueType::Integer:
|
||||||
property->fromInt64(message.read<int64_t>());
|
property->fromInt64(message.read<int64_t>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Float:
|
case ValueType::Float:
|
||||||
property->fromDouble(message.read<double>());
|
property->fromDouble(message.read<double>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::String:
|
case ValueType::String:
|
||||||
property->fromString(message.read<std::string>());
|
property->fromString(message.read<std::string>());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -194,7 +197,7 @@ bool Session::processMessage(const Message& message)
|
|||||||
catch(const std::exception&)
|
catch(const std::exception&)
|
||||||
{
|
{
|
||||||
// set property failed, send changed event with current value:
|
// set property failed, send changed event with current value:
|
||||||
objectPropertyChanged(*object, *property);
|
objectPropertyChanged(*property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +242,8 @@ void Session::writeObject(Message& message, const ObjectPtr& object)
|
|||||||
|
|
||||||
handle = m_handles.addItem(object);
|
handle = m_handles.addItem(object);
|
||||||
|
|
||||||
m_propertyChanged.emplace(handle, object->propertyChanged.connect(std::bind(&Session::objectPropertyChanged, this, std::placeholders::_1, std::placeholders::_2)));
|
m_propertyChanged.emplace(handle, object->propertyChanged.connect(std::bind(&Session::objectPropertyChanged, this, std::placeholders::_1)));
|
||||||
|
m_attributeChanged.emplace(handle, object->attributeChanged.connect(std::bind(&Session::objectAttributeChanged, this, std::placeholders::_1)));
|
||||||
|
|
||||||
message.write(handle);
|
message.write(handle);
|
||||||
message.write(object->getClassId());
|
message.write(object->getClassId());
|
||||||
@ -261,28 +265,28 @@ void Session::writeObject(Message& message, const ObjectPtr& object)
|
|||||||
message.write(property->type());
|
message.write(property->type());
|
||||||
switch(property->type())
|
switch(property->type())
|
||||||
{
|
{
|
||||||
case PropertyType::Boolean:
|
case ValueType::Boolean:
|
||||||
message.write(property->toBool());
|
message.write(property->toBool());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Enum:
|
case ValueType::Enum:
|
||||||
message.write(property->toInt64());
|
message.write(property->toInt64());
|
||||||
message.write(property->enumName());
|
message.write(property->enumName());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Integer:
|
case ValueType::Integer:
|
||||||
message.write(property->toInt64());
|
message.write(property->toInt64());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Float:
|
case ValueType::Float:
|
||||||
message.write(property->toDouble());
|
message.write(property->toDouble());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::String:
|
case ValueType::String:
|
||||||
message.write(property->toString());
|
message.write(property->toString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Object:
|
case ValueType::Object:
|
||||||
{
|
{
|
||||||
ObjectPtr obj = property->toObject();
|
ObjectPtr obj = property->toObject();
|
||||||
// TODO: assert(!obj || dynamic_cast<IdObject*>(obj.get()));
|
// TODO: assert(!obj || dynamic_cast<IdObject*>(obj.get()));
|
||||||
@ -298,6 +302,41 @@ void Session::writeObject(Message& message, const ObjectPtr& object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.writeBlock(); // attributes
|
||||||
|
|
||||||
|
for(const auto& it : item.attributes())
|
||||||
|
{
|
||||||
|
const AbstractAttribute& attribute = *it.second;
|
||||||
|
message.writeBlock(); // attribute
|
||||||
|
message.write(attribute.name());
|
||||||
|
message.write(attribute.type());
|
||||||
|
switch(attribute.type())
|
||||||
|
{
|
||||||
|
case ValueType::Boolean:
|
||||||
|
message.write(attribute.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Enum:
|
||||||
|
case ValueType::Integer:
|
||||||
|
message.write(attribute.toInt64());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Float:
|
||||||
|
message.write(attribute.toDouble());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::String:
|
||||||
|
message.write(attribute.toString());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
message.writeBlockEnd(); // end attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
message.writeBlockEnd(); // end attributes
|
||||||
message.writeBlockEnd(); // end item
|
message.writeBlockEnd(); // end item
|
||||||
}
|
}
|
||||||
message.writeBlockEnd(); // end items
|
message.writeBlockEnd(); // end items
|
||||||
@ -322,32 +361,63 @@ void Session::writeTableModel(Message& message, const TableModelPtr& model)
|
|||||||
message.writeBlockEnd(); // end model
|
message.writeBlockEnd(); // end model
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::objectPropertyChanged(Object& object, AbstractProperty& property)
|
void Session::objectPropertyChanged(AbstractProperty& property)
|
||||||
{
|
{
|
||||||
std::cout << "objectPropertyChanged " << property.name() << std::endl;
|
std::cout << "objectPropertyChanged " << property.name() << std::endl;
|
||||||
|
|
||||||
auto event = Message::newEvent(Message::Command::ObjectPropertyChanged);
|
auto event = Message::newEvent(Message::Command::ObjectPropertyChanged);
|
||||||
event->write(m_handles.getHandle(object.shared_from_this()));
|
event->write(m_handles.getHandle(property.object().shared_from_this()));
|
||||||
event->write(property.name());
|
event->write(property.name());
|
||||||
event->write(property.type());
|
event->write(property.type());
|
||||||
switch(property.type())
|
switch(property.type())
|
||||||
{
|
{
|
||||||
case PropertyType::Boolean:
|
case ValueType::Boolean:
|
||||||
event->write(property.toBool());
|
event->write(property.toBool());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Enum:
|
case ValueType::Enum:
|
||||||
case PropertyType::Integer:
|
case ValueType::Integer:
|
||||||
event->write(property.toInt64());
|
event->write(property.toInt64());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::Float:
|
case ValueType::Float:
|
||||||
event->write(property.toDouble());
|
event->write(property.toDouble());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyType::String:
|
case ValueType::String:
|
||||||
event->write(property.toString());
|
event->write(property.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_client->sendMessage(std::move(event));
|
m_client->sendMessage(std::move(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::objectAttributeChanged(AbstractAttribute& attribute)
|
||||||
|
{
|
||||||
|
std::cout << "objectAttributeChanged " << attribute.item().name() << "." << (int)attribute.name() << std::endl;
|
||||||
|
|
||||||
|
auto event = Message::newEvent(Message::Command::ObjectAttributeChanged);
|
||||||
|
event->write(m_handles.getHandle(attribute.item().object().shared_from_this()));
|
||||||
|
event->write(attribute.item().name());
|
||||||
|
event->write(attribute.name());
|
||||||
|
event->write(attribute.type());
|
||||||
|
switch(attribute.type())
|
||||||
|
{
|
||||||
|
case ValueType::Boolean:
|
||||||
|
event->write(attribute.toBool());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Enum:
|
||||||
|
case ValueType::Integer:
|
||||||
|
//event->write(attribute.toInt64());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::Float:
|
||||||
|
//event->write(attribute.toDouble());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueType::String:
|
||||||
|
//event->write(attribute.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_client->sendMessage(std::move(event));
|
||||||
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
class AbstractProperty;
|
class AbstractProperty;
|
||||||
|
class AbstractAttribute;
|
||||||
|
|
||||||
class Session : public std::enable_shared_from_this<Session>
|
class Session : public std::enable_shared_from_this<Session>
|
||||||
{
|
{
|
||||||
@ -46,13 +47,15 @@ class Session : public std::enable_shared_from_this<Session>
|
|||||||
boost::uuids::uuid m_uuid;
|
boost::uuids::uuid m_uuid;
|
||||||
Handles m_handles;
|
Handles m_handles;
|
||||||
std::unordered_map<Handle, boost::signals2::connection> m_propertyChanged;
|
std::unordered_map<Handle, boost::signals2::connection> m_propertyChanged;
|
||||||
|
std::unordered_map<Handle, boost::signals2::connection> m_attributeChanged;
|
||||||
|
|
||||||
bool processMessage(const Message& message);
|
bool processMessage(const Message& message);
|
||||||
|
|
||||||
void writeObject(Message& message, const ObjectPtr& object);
|
void writeObject(Message& message, const ObjectPtr& object);
|
||||||
void writeTableModel(Message& message, const TableModelPtr& model);
|
void writeTableModel(Message& message, const TableModelPtr& model);
|
||||||
|
|
||||||
void objectPropertyChanged(Object& object, AbstractProperty& property);
|
void objectPropertyChanged(AbstractProperty& property);
|
||||||
|
void objectAttributeChanged(AbstractAttribute& attribute);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Session(const std::shared_ptr<Client>& client);
|
Session(const std::shared_ptr<Client>& client);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ Traintastic::Traintastic(const std::filesystem::path& dataDir) :
|
|||||||
{
|
{
|
||||||
assert(world);
|
assert(world);
|
||||||
console->info(id, "Mode changed to <TODO> " + std::to_string((int)value));
|
console->info(id, "Mode changed to <TODO> " + std::to_string((int)value));
|
||||||
//world->modeChanged(value);
|
world->modeChanged(value);
|
||||||
},
|
},
|
||||||
[this](TraintasticMode& newValue)
|
[this](TraintasticMode& newValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* server/src/core/propertytypetraits.hpp
|
* server/src/core/valuetypetraits.hpp
|
||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* This file is part of the traintastic source code.
|
||||||
*
|
*
|
||||||
@ -20,22 +20,25 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
#ifndef SERVER_CORE_VALUETYPETRAITS_HPP
|
||||||
#define SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
#define SERVER_CORE_VALUETYPETRAITS_HPP
|
||||||
|
|
||||||
#include <enum/propertytype.hpp>
|
#include <enum/valuetype.hpp>
|
||||||
#include "objectptr.hpp"
|
#include "objectptr.hpp"
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct property_type
|
struct value_type
|
||||||
{
|
{
|
||||||
static constexpr PropertyType value =
|
static constexpr ValueType value =
|
||||||
std::is_same<T, bool>::value ? PropertyType::Boolean : (
|
std::is_same_v<T, bool> ? ValueType::Boolean : (
|
||||||
std::is_enum<T>::value ? PropertyType::Enum : (
|
std::is_enum_v<T> ? ValueType::Enum : (
|
||||||
std::is_integral<T>::value ? PropertyType::Integer : (
|
std::is_integral_v<T> ? ValueType::Integer : (
|
||||||
std::is_floating_point<T>::value ? PropertyType::Float : (
|
std::is_floating_point_v<T> ? ValueType::Float : (
|
||||||
std::is_same<T, std::string>::value ? PropertyType::String : (
|
std::is_same_v<T, std::string> ? ValueType::String : (
|
||||||
PropertyType::Invalid)))));
|
ValueType::Invalid)))));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr ValueType value_type_v = value_type<T>::value;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -103,6 +103,14 @@ ObjectPtr World::getObject(const std::string& _id) const
|
|||||||
return ObjectPtr();
|
return ObjectPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::modeChanged(TraintasticMode mode)
|
||||||
|
{
|
||||||
|
Traintastic::instance->console->debug(id, "World::modeChanged");
|
||||||
|
|
||||||
|
for(auto& it : m_objects)
|
||||||
|
it.second.lock()->modeChanged(mode);
|
||||||
|
}
|
||||||
|
|
||||||
void World::load()
|
void World::load()
|
||||||
{
|
{
|
||||||
std::ifstream file(m_filename);
|
std::ifstream file(m_filename);
|
||||||
@ -218,7 +226,7 @@ void World::save()
|
|||||||
for(auto& item : object->interfaceItems())
|
for(auto& item : object->interfaceItems())
|
||||||
if(AbstractProperty* property = dynamic_cast<AbstractProperty*>(&item.second))
|
if(AbstractProperty* property = dynamic_cast<AbstractProperty*>(&item.second))
|
||||||
{
|
{
|
||||||
if(property->type() == PropertyType::Object)
|
if(property->type() == ValueType::Object)
|
||||||
{
|
{
|
||||||
if(IdObject* idObject = dynamic_cast<IdObject*>(property->toObject().get()))
|
if(IdObject* idObject = dynamic_cast<IdObject*>(property->toObject().get()))
|
||||||
objectData[property->name()] = idObject->id.toJSON();
|
objectData[property->name()] = idObject->id.toJSON();
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
class World : public Object
|
class World : public Object
|
||||||
{
|
{
|
||||||
friend class IdObject;
|
friend class IdObject;
|
||||||
|
friend class Traintastic;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
@ -47,6 +48,7 @@ class World : public Object
|
|||||||
boost::uuids::uuid m_uuid;
|
boost::uuids::uuid m_uuid;
|
||||||
std::unordered_map<std::string, std::weak_ptr<Object>> m_objects;
|
std::unordered_map<std::string, std::weak_ptr<Object>> m_objects;
|
||||||
|
|
||||||
|
void modeChanged(TraintasticMode mode);
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -40,7 +40,8 @@ CommandStation::CommandStation(const std::weak_ptr<World>& world, const std::str
|
|||||||
m_interfaceItems.add(online);
|
m_interfaceItems.add(online);
|
||||||
m_interfaceItems.add(status);
|
m_interfaceItems.add(status);
|
||||||
m_interfaceItems.add(decoders);
|
m_interfaceItems.add(decoders);
|
||||||
m_interfaceItems.add(notes);
|
m_interfaceItems.add(notes)
|
||||||
|
.addAttributeCategory(Category::Notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<Decoder>& CommandStation::getDecoder(DecoderProtocol protocol, uint16_t address, bool longAddress) const
|
const std::shared_ptr<Decoder>& CommandStation::getDecoder(DecoderProtocol protocol, uint16_t address, bool longAddress) const
|
||||||
|
|||||||
@ -39,14 +39,16 @@
|
|||||||
#define Z21_LAN_X_UNKNOWN_COMMAND 0x82
|
#define Z21_LAN_X_UNKNOWN_COMMAND 0x82
|
||||||
#define Z21_LAN_X_BC_STOPPED 0x81
|
#define Z21_LAN_X_BC_STOPPED 0x81
|
||||||
#define Z21_LAN_X_LOCO_INFO 0xEF
|
#define Z21_LAN_X_LOCO_INFO 0xEF
|
||||||
|
#define Z21_LAN_SET_BROADCASTFLAGS 0x50
|
||||||
|
#define Z21_LAN_GET_BROADCASTFLAGS 0x51
|
||||||
#define Z21_LAN_SYSTEMSTATE_DATACHANGED 0x84
|
#define Z21_LAN_SYSTEMSTATE_DATACHANGED 0x84
|
||||||
#define Z21_LAN_SYSTEMSTATE_GETDATA 0x85
|
#define Z21_LAN_SYSTEMSTATE_GETDATA 0x85
|
||||||
|
|
||||||
#define Z21_HWT_Z21_OLD 0x00000200 //!< „black Z21” (hardware variant from 2012)
|
#define Z21_HWT_Z21_OLD 0x00000200 //!< „black Z21” (hardware variant from 2012)
|
||||||
#define Z21_HWT_Z21_NEW 0x00000201 //!< „black Z21”(hardware variant from 2013)
|
#define Z21_HWT_Z21_NEW 0x00000201 //!< „black Z21”(hardware variant from 2013)
|
||||||
#define Z21_HWT_SMARTRAIL 0x00000202 //!< SmartRail (from 2012)
|
#define Z21_HWT_SMARTRAIL 0x00000202 //!< SmartRail (from 2012)
|
||||||
#define Z21_HWT_z21_SMALL 0x00000203 //!< „white z21” starter set variant (from 2013)
|
#define Z21_HWT_Z21_SMALL 0x00000203 //!< „white z21” starter set variant (from 2013)
|
||||||
#define Z21_HWT_z21_START 0x00000204 //!< „z21 start” starter set variant (from 2016)
|
#define Z21_HWT_Z21_START 0x00000204 //!< „z21 start” starter set variant (from 2016)
|
||||||
|
|
||||||
#define Z21_CENTRALSTATE_EMERGENCYSTOP 0x01 //!< The emergency stop is switched on
|
#define Z21_CENTRALSTATE_EMERGENCYSTOP 0x01 //!< The emergency stop is switched on
|
||||||
#define Z21_CENTRALSTATE_TRACKVOLTAGEOFF 0x02 //!< The track voltage is switched off
|
#define Z21_CENTRALSTATE_TRACKVOLTAGEOFF 0x02 //!< The track voltage is switched off
|
||||||
@ -153,6 +155,23 @@ struct z21_lan_x_set_track_power_on : z21_lan_x
|
|||||||
}
|
}
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct z21_lan_x_get_loco_info : z21_lan_x
|
||||||
|
{
|
||||||
|
uint8_t db0;
|
||||||
|
uint8_t addressHigh;
|
||||||
|
uint8_t addressLow;
|
||||||
|
uint8_t checksum;
|
||||||
|
|
||||||
|
z21_lan_x_get_loco_info() :
|
||||||
|
db0{0xF0}
|
||||||
|
{
|
||||||
|
dataLen = sizeof(z21_lan_x_get_loco_info);
|
||||||
|
header = Z21_LAN_X;
|
||||||
|
xheader = 0xE3;
|
||||||
|
}
|
||||||
|
} __attribute__((packed));
|
||||||
|
//static_assert(sizeof(z21_lan_x_get_loco_info) == 0x07);
|
||||||
|
|
||||||
struct z21_lan_x_loco_info : z21_lan_x
|
struct z21_lan_x_loco_info : z21_lan_x
|
||||||
{
|
{
|
||||||
uint8_t addressHigh;
|
uint8_t addressHigh;
|
||||||
@ -197,6 +216,29 @@ struct z21_lan_systemstate_getdata : z21_lan_header
|
|||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
static_assert(sizeof(z21_lan_systemstate_getdata) == 0x04);
|
static_assert(sizeof(z21_lan_systemstate_getdata) == 0x04);
|
||||||
|
|
||||||
|
struct z21_lan_set_broadcastflags : z21_lan_header
|
||||||
|
{
|
||||||
|
uint32_t broadcastFlags; // LE
|
||||||
|
|
||||||
|
z21_lan_set_broadcastflags(uint32_t _broadcastFlags = 0) :
|
||||||
|
broadcastFlags{_broadcastFlags}
|
||||||
|
{
|
||||||
|
dataLen = sizeof(z21_lan_set_broadcastflags);
|
||||||
|
header = Z21_LAN_SET_BROADCASTFLAGS;
|
||||||
|
}
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(z21_lan_set_broadcastflags) == 0x08);
|
||||||
|
|
||||||
|
struct z21_lan_get_broadcastflags : z21_lan_header
|
||||||
|
{
|
||||||
|
z21_lan_get_broadcastflags()
|
||||||
|
{
|
||||||
|
dataLen = sizeof(z21_lan_get_broadcastflags);
|
||||||
|
header = Z21_LAN_GET_BROADCASTFLAGS;
|
||||||
|
}
|
||||||
|
} __attribute__((packed));
|
||||||
|
static_assert(sizeof(z21_lan_get_broadcastflags) == 0x04);
|
||||||
|
|
||||||
struct z21_lan_systemstate_datachanged : z21_lan_header
|
struct z21_lan_systemstate_datachanged : z21_lan_header
|
||||||
{
|
{
|
||||||
int16_t mainCurrent; //!< Current on the main track in mA
|
int16_t mainCurrent; //!< Current on the main track in mA
|
||||||
|
|||||||
@ -63,33 +63,43 @@ Z21::Z21(const std::weak_ptr<World>& world, const std::string& _id) :
|
|||||||
m_socket{Traintastic::instance->ioContext()},
|
m_socket{Traintastic::instance->ioContext()},
|
||||||
hostname{this, "hostname", "", PropertyFlags::AccessWCC},
|
hostname{this, "hostname", "", PropertyFlags::AccessWCC},
|
||||||
port{this, "port", 21105, PropertyFlags::AccessWCC},
|
port{this, "port", 21105, PropertyFlags::AccessWCC},
|
||||||
serialNumber{this, "serial_number", 0, PropertyFlags::AccessRRR},
|
serialNumber{this, "serial_number", "", PropertyFlags::AccessRRR},
|
||||||
hardwareType{this, "hardware_type", "", PropertyFlags::AccessRRR},
|
hardwareType{this, "hardware_type", "", PropertyFlags::AccessRRR},
|
||||||
firmwareVersion{this, "firmware_version", "", PropertyFlags::AccessRRR},
|
firmwareVersion{this, "firmware_version", "", PropertyFlags::AccessRRR},
|
||||||
emergencyStop{this, "emergency_stop", false, PropertyFlags::TODO,
|
emergencyStop{this, "emergency_stop", false, PropertyFlags::TODO,
|
||||||
[this](bool value)
|
[this](bool value)
|
||||||
{
|
{
|
||||||
if(value)
|
if(online && value)
|
||||||
send(z21_lan_x_set_stop());
|
send(z21_lan_x_set_stop());
|
||||||
}},
|
}},
|
||||||
trackVoltageOff{this, "track_voltage_off", false, PropertyFlags::TODO,
|
trackVoltageOff{this, "track_voltage_off", false, PropertyFlags::TODO,
|
||||||
[this](bool value)
|
[this](bool value)
|
||||||
|
{
|
||||||
|
if(online)
|
||||||
{
|
{
|
||||||
if(value)
|
if(value)
|
||||||
send(z21_lan_x_set_track_power_off());
|
send(z21_lan_x_set_track_power_off());
|
||||||
else
|
else
|
||||||
send(z21_lan_x_set_track_power_on());
|
send(z21_lan_x_set_track_power_on());
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
{
|
{
|
||||||
name = "Z21";
|
name = "Z21";
|
||||||
|
|
||||||
m_interfaceItems.add(hostname);
|
m_interfaceItems.insertBefore(hostname, notes)
|
||||||
m_interfaceItems.add(port);
|
.addAttributeEnabled(true);
|
||||||
m_interfaceItems.add(serialNumber);
|
m_interfaceItems.insertBefore(port, notes)
|
||||||
m_interfaceItems.add(hardwareType);
|
.addAttributeEnabled(true);
|
||||||
m_interfaceItems.add(firmwareVersion);
|
m_interfaceItems.insertBefore(serialNumber, notes)
|
||||||
m_interfaceItems.add(emergencyStop);
|
.addAttributeCategory(Category::Info);
|
||||||
m_interfaceItems.add(trackVoltageOff);
|
m_interfaceItems.insertBefore(hardwareType, notes)
|
||||||
|
.addAttributeCategory(Category::Info);
|
||||||
|
m_interfaceItems.insertBefore(firmwareVersion, notes)
|
||||||
|
.addAttributeCategory(Category::Info);
|
||||||
|
m_interfaceItems.insertBefore(emergencyStop, notes)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
|
m_interfaceItems.insertBefore(trackVoltageOff, notes)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Z21::isDecoderSupported(Decoder& decoder) const
|
bool Z21::isDecoderSupported(Decoder& decoder) const
|
||||||
@ -194,13 +204,41 @@ bool Z21::setOnline(bool& value)
|
|||||||
Traintastic::instance->console->error(id, "socket.bind: " + ec.message());
|
Traintastic::instance->console->error(id, "socket.bind: " + ec.message());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
receive();
|
||||||
|
|
||||||
|
send(z21_lan_set_broadcastflags(/*0x00010000 |*/ 0x00000100 | 0x00000001));
|
||||||
|
|
||||||
// try to communicate with Z21
|
// try to communicate with Z21
|
||||||
|
send(z21_lan_get_broadcastflags());
|
||||||
send(z21_lan_get_serial_number());
|
send(z21_lan_get_serial_number());
|
||||||
send(z21_lan_get_hwinfo());
|
send(z21_lan_get_hwinfo());
|
||||||
send(z21_lan_systemstate_getdata());
|
send(z21_lan_systemstate_getdata());
|
||||||
|
/*
|
||||||
|
for(auto& decoder : decoders)
|
||||||
|
{
|
||||||
|
z21_lan_x_get_loco_info cmd;
|
||||||
|
send(cmd);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
hostname.setAttributeEnabled(false);
|
||||||
|
port.setAttributeEnabled(false);
|
||||||
|
emergencyStop.setAttributeEnabled(true);
|
||||||
|
trackVoltageOff.setAttributeEnabled(true);
|
||||||
}
|
}
|
||||||
else if(m_socket.is_open() && !value)
|
else if(m_socket.is_open() && !value)
|
||||||
{
|
{
|
||||||
|
send(z21_lan_logoff());
|
||||||
|
|
||||||
|
serialNumber = "";
|
||||||
|
hardwareType = "";
|
||||||
|
firmwareVersion = "";
|
||||||
|
|
||||||
|
hostname.setAttributeEnabled(true);
|
||||||
|
port.setAttributeEnabled(true);
|
||||||
|
emergencyStop.setAttributeEnabled(false);
|
||||||
|
trackVoltageOff.setAttributeEnabled(false);
|
||||||
|
|
||||||
m_socket.close();
|
m_socket.close();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -221,9 +259,9 @@ void Z21::receive()
|
|||||||
case Z21_LAN_GET_SERIAL_NUMBER:
|
case Z21_LAN_GET_SERIAL_NUMBER:
|
||||||
{
|
{
|
||||||
EventLoop::call(
|
EventLoop::call(
|
||||||
[this, value=static_cast<const z21_lan_get_serial_number_reply*>(cmd)->serialNumber]()
|
[this, value=std::to_string(static_cast<const z21_lan_get_serial_number_reply*>(cmd)->serialNumber)]()
|
||||||
{
|
{
|
||||||
serialNumber = value;
|
serialNumber.setValueInternal(value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -243,10 +281,10 @@ void Z21::receive()
|
|||||||
case Z21_HWT_SMARTRAIL:
|
case Z21_HWT_SMARTRAIL:
|
||||||
hwType = "SmartRail (from 2012)";
|
hwType = "SmartRail (from 2012)";
|
||||||
break;
|
break;
|
||||||
case Z21_HWT_z21_SMALL:
|
case Z21_HWT_Z21_SMALL:
|
||||||
hwType = "White Z21 (starter set variant from 2013)";
|
hwType = "White Z21 (starter set variant from 2013)";
|
||||||
break;
|
break;
|
||||||
case Z21_HWT_z21_START :
|
case Z21_HWT_Z21_START :
|
||||||
hwType = "Z21 start (starter set variant from 2016)";
|
hwType = "Z21 start (starter set variant from 2016)";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -259,8 +297,8 @@ void Z21::receive()
|
|||||||
EventLoop::call(
|
EventLoop::call(
|
||||||
[this, hwType, fwVersion]()
|
[this, hwType, fwVersion]()
|
||||||
{
|
{
|
||||||
hardwareType = hwType;
|
hardwareType.setValueInternal(hwType);
|
||||||
firmwareVersion = fwVersion;
|
firmwareVersion.setValueInternal(fwVersion);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -294,13 +332,13 @@ void Z21::receive()
|
|||||||
if((speedStepMode == 0 && decoder->speedSteps == 14) ||
|
if((speedStepMode == 0 && decoder->speedSteps == 14) ||
|
||||||
(speedStepMode == 2 && decoder->speedSteps == 28) ||
|
(speedStepMode == 2 && decoder->speedSteps == 28) ||
|
||||||
(speedStepMode == 4 && decoder->speedSteps == 126))
|
(speedStepMode == 4 && decoder->speedSteps == 126))
|
||||||
decoder->speedStep = speedStep;
|
decoder->speedStep.setValueInternal(speedStep);
|
||||||
|
|
||||||
for(auto& function : *decoder->functions)
|
for(auto& function : *decoder->functions)
|
||||||
{
|
{
|
||||||
const uint8_t number = function->number;
|
const uint8_t number = function->number;
|
||||||
if(number <= 28)
|
if(number <= 28)
|
||||||
function->value = functions & (1 << number);
|
function->value.setValueInternal(functions & (1 << number));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -315,7 +353,7 @@ void Z21::receive()
|
|||||||
EventLoop::call(
|
EventLoop::call(
|
||||||
[this]()
|
[this]()
|
||||||
{
|
{
|
||||||
emergencyStop = true;
|
emergencyStop.setValueInternal(true);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -331,8 +369,8 @@ void Z21::receive()
|
|||||||
EventLoop::call(
|
EventLoop::call(
|
||||||
[this, state]()
|
[this, state]()
|
||||||
{
|
{
|
||||||
emergencyStop = state.centralState & Z21_CENTRALSTATE_EMERGENCYSTOP;
|
emergencyStop.setValueInternal(state.centralState & Z21_CENTRALSTATE_EMERGENCYSTOP);
|
||||||
trackVoltageOff = state.centralState & Z21_CENTRALSTATE_TRACKVOLTAGEOFF;
|
trackVoltageOff.setValueInternal(state.centralState & Z21_CENTRALSTATE_TRACKVOLTAGEOFF);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class Z21 : public CommandStation
|
|||||||
|
|
||||||
Property<std::string> hostname;
|
Property<std::string> hostname;
|
||||||
Property<uint16_t> port;
|
Property<uint16_t> port;
|
||||||
Property<uint32_t> serialNumber;
|
Property<std::string> serialNumber;
|
||||||
Property<std::string> hardwareType;
|
Property<std::string> hardwareType;
|
||||||
Property<std::string> firmwareVersion;
|
Property<std::string> firmwareVersion;
|
||||||
Property<bool> emergencyStop;
|
Property<bool> emergencyStop;
|
||||||
|
|||||||
@ -81,13 +81,20 @@ Decoder::Decoder(const std::weak_ptr<World>& world, const std::string& _id) :
|
|||||||
notes{this, "notes", "", PropertyFlags::AccessWWW}
|
notes{this, "notes", "", PropertyFlags::AccessWWW}
|
||||||
{
|
{
|
||||||
m_interfaceItems.add(name);
|
m_interfaceItems.add(name);
|
||||||
m_interfaceItems.add(commandStation);
|
m_interfaceItems.add(commandStation)
|
||||||
m_interfaceItems.add(protocol);
|
.addAttributeEnabled(false);
|
||||||
m_interfaceItems.add(address);
|
m_interfaceItems.add(protocol)
|
||||||
m_interfaceItems.add(emergencyStop);
|
.addAttributeEnabled(false);
|
||||||
m_interfaceItems.add(direction);
|
m_interfaceItems.add(address)
|
||||||
m_interfaceItems.add(speedSteps);
|
.addAttributeEnabled(false);
|
||||||
m_interfaceItems.add(speedStep);
|
m_interfaceItems.add(emergencyStop)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
|
m_interfaceItems.add(direction)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
|
m_interfaceItems.add(speedSteps)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
|
m_interfaceItems.add(speedStep)
|
||||||
|
.addAttributeEnabled(false);
|
||||||
m_interfaceItems.add(functions);
|
m_interfaceItems.add(functions);
|
||||||
m_interfaceItems.add(notes);
|
m_interfaceItems.add(notes);
|
||||||
}
|
}
|
||||||
@ -101,6 +108,20 @@ const std::shared_ptr<DecoderFunction>& Decoder::getFunction(uint32_t number) co
|
|||||||
return DecoderFunction::null;
|
return DecoderFunction::null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Decoder::modeChanged(TraintasticMode mode)
|
||||||
|
{
|
||||||
|
IdObject::modeChanged(mode);
|
||||||
|
|
||||||
|
commandStation.setAttributeEnabled(mode == TraintasticMode::Edit);
|
||||||
|
protocol.setAttributeEnabled(mode == TraintasticMode::Edit);
|
||||||
|
address.setAttributeEnabled(mode == TraintasticMode::Edit);
|
||||||
|
speedSteps.setAttributeEnabled(mode == TraintasticMode::Edit);
|
||||||
|
speedStep.setAttributeEnabled(mode == TraintasticMode::Run);
|
||||||
|
|
||||||
|
if(mode == TraintasticMode::Edit)
|
||||||
|
speedStep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Decoder::changed(DecoderChangeFlags changes, uint32_t functionNumber)
|
void Decoder::changed(DecoderChangeFlags changes, uint32_t functionNumber)
|
||||||
{
|
{
|
||||||
if(commandStation)
|
if(commandStation)
|
||||||
|
|||||||
@ -46,6 +46,7 @@ class Decoder : public IdObject
|
|||||||
friend class DecoderFunction;
|
friend class DecoderFunction;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void modeChanged(TraintasticMode mode) final;
|
||||||
void changed(DecoderChangeFlags changes, uint32_t functionNumber = 0);
|
void changed(DecoderChangeFlags changes, uint32_t functionNumber = 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
6
server/src/utils/attributes.hpp
Normale Datei
6
server/src/utils/attributes.hpp
Normale Datei
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef ATTRIBUTES_HPP
|
||||||
|
#define ATTRIBUTES_HPP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ATTRIBUTES_HPP
|
||||||
38
shared/src/enum/attributename.hpp
Normale Datei
38
shared/src/enum/attributename.hpp
Normale Datei
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* shared/src/enum/propertytype.hpp
|
||||||
|
*
|
||||||
|
* This file is part of the traintastic source code.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Reinder Feenstra
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SHARED_ENUM_ATTIRBUTE_HPP
|
||||||
|
#define SHARED_ENUM_ATTIRBUTE_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class AttributeName : uint16_t
|
||||||
|
{
|
||||||
|
Visible = 0,
|
||||||
|
Enabled = 1,
|
||||||
|
Min = 2,
|
||||||
|
Max = 3,
|
||||||
|
Category = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
37
shared/src/enum/category.hpp
Normale Datei
37
shared/src/enum/category.hpp
Normale Datei
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* shared/src/enum/category.hpp
|
||||||
|
*
|
||||||
|
* This file is part of the traintastic source code.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Reinder Feenstra
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SHARED_ENUM_CATEGORY_HPP
|
||||||
|
#define SHARED_ENUM_CATEGORY_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class Category : uint16_t
|
||||||
|
{
|
||||||
|
General = 0,
|
||||||
|
Notes = 1,
|
||||||
|
Status = 2,
|
||||||
|
Info = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* shared/src/enum/propertytype.hpp
|
* shared/src/enum/valuetype.hpp
|
||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* This file is part of the traintastic source code.
|
||||||
*
|
*
|
||||||
@ -20,12 +20,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SHARED_ENUM_PROPERTYTYPE_HPP
|
#ifndef SHARED_ENUM_VALUETYPE_HPP
|
||||||
#define SHARED_ENUM_PROPERTYTYPE_HPP
|
#define SHARED_ENUM_VALUETYPE_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
enum class PropertyType : uint8_t
|
enum class ValueType : uint8_t
|
||||||
{
|
{
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
Boolean = 1,
|
Boolean = 1,
|
||||||
@ -59,12 +59,14 @@ class Message
|
|||||||
ReleaseObject = 15,
|
ReleaseObject = 15,
|
||||||
ObjectSetProperty = 16,
|
ObjectSetProperty = 16,
|
||||||
ObjectPropertyChanged = 17,
|
ObjectPropertyChanged = 17,
|
||||||
GetTableModel = 18,
|
ObjectAttributeChanged = 18,
|
||||||
ReleaseTableModel = 19,
|
|
||||||
TableModelColumnHeadersChanged = 20,
|
GetTableModel = 19,
|
||||||
TableModelRowCountChanged = 21,
|
ReleaseTableModel = 20,
|
||||||
TableModelSetRegion = 22,
|
TableModelColumnHeadersChanged = 21,
|
||||||
TableModelUpdateRegion = 23,
|
TableModelRowCountChanged = 22,
|
||||||
|
TableModelSetRegion = 23,
|
||||||
|
TableModelUpdateRegion = 24,
|
||||||
|
|
||||||
Discover = 255,
|
Discover = 255,
|
||||||
};
|
};
|
||||||
|
|||||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren