WIP: attribute support
Dieser Commit ist enthalten in:
Ursprung
33f4db0d4b
Commit
af084bff45
@ -36,6 +36,7 @@
|
||||
#include "network/object.hpp"
|
||||
#include "network/property.hpp"
|
||||
#include "subwindow/hardwarelistsubwindow.hpp"
|
||||
#include "subwindow/objecteditsubwindow.hpp"
|
||||
#include "subwindow/serversettingssubwindow.hpp"
|
||||
#include "subwindow/serverconsolesubwindow.hpp"
|
||||
|
||||
@ -47,6 +48,8 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||
QMainWindow(parent),
|
||||
m_mdiArea{new QMdiArea()}
|
||||
{
|
||||
instance = this;
|
||||
|
||||
setWindowTitle("Traintastic");
|
||||
|
||||
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()
|
||||
{
|
||||
if(!m_mdiSubWindow.hardwareList)
|
||||
|
||||
@ -25,10 +25,12 @@
|
||||
#define MAINWINDOW_HPP
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <enum/traintasticmode.hpp>
|
||||
|
||||
class QMdiArea;
|
||||
class QActionGroup;
|
||||
class ObjectEditSubWindow;
|
||||
class HardwareListSubWindow;
|
||||
class ServerSettingsSubWindow;
|
||||
class ServerConsoleSubWindow;
|
||||
@ -41,6 +43,7 @@ class MainWindow : public QMainWindow
|
||||
QMdiArea* m_mdiArea;
|
||||
struct
|
||||
{
|
||||
QMap<QString, ObjectEditSubWindow*> objectEdit;
|
||||
HardwareListSubWindow* hardwareList = nullptr;
|
||||
ServerSettingsSubWindow* serverSettings = nullptr;
|
||||
ServerConsoleSubWindow* serverConsole = nullptr;
|
||||
@ -73,6 +76,7 @@ class MainWindow : public QMainWindow
|
||||
void exportWorld();
|
||||
void toggleFullScreen();
|
||||
void showHardware();
|
||||
|
||||
void showServerSettings();
|
||||
void showServerConsole();
|
||||
void showAbout();
|
||||
@ -80,11 +84,14 @@ class MainWindow : public QMainWindow
|
||||
void updateModeActions();
|
||||
|
||||
public:
|
||||
inline static MainWindow* instance = nullptr;
|
||||
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
public slots:
|
||||
void connectToServer();
|
||||
void showObjectEdit(const QString& id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
#define CLIENT_NETWORK_ABSTRACTPROPERTY_HPP
|
||||
|
||||
#include "interfaceitem.hpp"
|
||||
#include <enum/propertytype.hpp>
|
||||
#include <enum/valuetype.hpp>
|
||||
|
||||
class Object;
|
||||
|
||||
@ -33,16 +33,16 @@ class AbstractProperty : public InterfaceItem
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
const PropertyType m_type;
|
||||
const ValueType m_type;
|
||||
|
||||
public:
|
||||
explicit AbstractProperty(Object& object, const QString& name, PropertyType type) :
|
||||
explicit AbstractProperty(Object& object, const QString& name, ValueType type) :
|
||||
InterfaceItem(object, name),
|
||||
m_type{type}
|
||||
{
|
||||
}
|
||||
|
||||
PropertyType type() const { return m_type; }
|
||||
ValueType type() const { return m_type; }
|
||||
|
||||
virtual const QString& enumName() const = 0;
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
#include "property.hpp"
|
||||
#include "tablemodel.hpp"
|
||||
#include <enum/interfaceitemtype.hpp>
|
||||
#include <enum/propertytype.hpp>
|
||||
#include <enum/valuetype.hpp>
|
||||
|
||||
Client* Client::instance = nullptr;
|
||||
|
||||
@ -125,7 +125,7 @@ void Client::setPropertyBool(Property& property, bool value)
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Boolean);
|
||||
event->write(ValueType::Boolean);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
@ -135,7 +135,7 @@ void Client::setPropertyInt64(Property& property, int64_t value)
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Integer);
|
||||
event->write(ValueType::Integer);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
@ -145,7 +145,7 @@ void Client::setPropertyDouble(Property& property, double value)
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Float);
|
||||
event->write(ValueType::Float);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
@ -155,7 +155,7 @@ void Client::setPropertyString(Property& property, const QString& value)
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::String);
|
||||
event->write(ValueType::String);
|
||||
event->write(value.toUtf8());
|
||||
send(event);
|
||||
}
|
||||
@ -229,52 +229,96 @@ ObjectPtr Client::readObject(const Message& message)
|
||||
while(!message.endOfBlock())
|
||||
{
|
||||
message.readBlock(); // item
|
||||
InterfaceItem* item = nullptr;
|
||||
const QString name = QString::fromLatin1(message.read<QByteArray>());
|
||||
const InterfaceItemType type = message.read<InterfaceItemType>();
|
||||
switch(type)
|
||||
{
|
||||
case InterfaceItemType::Property:
|
||||
{
|
||||
const PropertyType propertyType = message.read<PropertyType>();
|
||||
const ValueType type = message.read<ValueType>();
|
||||
QVariant value;
|
||||
switch(propertyType)
|
||||
switch(type)
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
case ValueType::Boolean:
|
||||
value = message.read<bool>();
|
||||
break;
|
||||
|
||||
case PropertyType::Enum:
|
||||
case PropertyType::Integer:
|
||||
case ValueType::Enum:
|
||||
case ValueType::Integer:
|
||||
value = message.read<qint64>();
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
case ValueType::Float:
|
||||
value = message.read<double>();
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
case ValueType::String:
|
||||
value = QString::fromUtf8(message.read<QByteArray>());
|
||||
break;
|
||||
|
||||
case PropertyType::Object:
|
||||
case ValueType::Object:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case PropertyType::Invalid:
|
||||
case ValueType::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
// Q_ASSERT(value.isValid());
|
||||
if(Q_LIKELY(value.isValid()))
|
||||
{
|
||||
Property* p = new Property(*obj, name, propertyType, value);
|
||||
if(propertyType == PropertyType::Enum)
|
||||
Property* p = new Property(*obj, name, type, value);
|
||||
if(type == ValueType::Enum)
|
||||
p->m_enumName = QString::fromLatin1(message.read<QByteArray>());
|
||||
obj->m_interfaceItems.add(*p);
|
||||
item = p;
|
||||
}
|
||||
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 items
|
||||
@ -329,9 +373,9 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
{
|
||||
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>();
|
||||
property->m_value = value;
|
||||
@ -339,8 +383,8 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
emit property->valueChangedBool(value);
|
||||
break;
|
||||
}
|
||||
case PropertyType::Integer:
|
||||
case PropertyType::Enum:
|
||||
case ValueType::Integer:
|
||||
case ValueType::Enum:
|
||||
{
|
||||
const qlonglong value = message->read<qlonglong>();
|
||||
property->m_value = value;
|
||||
@ -350,7 +394,7 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
emit property->valueChangedInt(static_cast<int>(value));
|
||||
break;
|
||||
}
|
||||
case PropertyType::Float:
|
||||
case ValueType::Float:
|
||||
{
|
||||
const double value = message->read<double>();
|
||||
property->m_value = value;
|
||||
@ -358,7 +402,7 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
emit property->valueChangedDouble(value);
|
||||
break;
|
||||
}
|
||||
case PropertyType::String:
|
||||
case ValueType::String:
|
||||
{
|
||||
const QString value = QString::fromUtf8(message->read<QByteArray>());
|
||||
property->m_value = value;
|
||||
@ -371,6 +415,42 @@ void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
}
|
||||
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:
|
||||
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
||||
{
|
||||
|
||||
@ -28,3 +28,18 @@ InterfaceItem::InterfaceItem(Object& object, const QString& 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
|
||||
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <enum/attributename.hpp>
|
||||
|
||||
class Object;
|
||||
|
||||
@ -31,14 +34,30 @@ class InterfaceItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Client;
|
||||
|
||||
protected:
|
||||
const QString m_name;
|
||||
QMap<AttributeName, QVariant> m_attributes;
|
||||
|
||||
public:
|
||||
explicit InterfaceItem(Object& object, const QString& name);
|
||||
|
||||
const QString& name() 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
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include "property.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),
|
||||
m_value{value}
|
||||
{
|
||||
|
||||
@ -40,7 +40,7 @@ class Property : public AbstractProperty
|
||||
QString m_enumName;
|
||||
|
||||
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; }
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ HardwareListSubWindow::HardwareListSubWindow(QWidget* parent) :
|
||||
QMdiSubWindow(parent)
|
||||
{
|
||||
setWindowTitle(tr("Hardware"));
|
||||
//setWindowIcon(QIcon(":/dark/hardware.svg"));
|
||||
setWindowIcon(QIcon(":/dark/hardware.svg"));
|
||||
setWidget(new HardwareWidget(this));
|
||||
|
||||
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/propertytextedit.hpp"
|
||||
#include "../widget/propertydirectioncontrol.hpp"
|
||||
#include <enum/category.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) :
|
||||
QWidget(parent),
|
||||
m_id{id}
|
||||
@ -67,31 +83,34 @@ ObjectEditWidget::~ObjectEditWidget()
|
||||
|
||||
void ObjectEditWidget::buildForm()
|
||||
{
|
||||
QMap<QString, QWidget*> tabs;
|
||||
QMap<Category, QWidget*> tabs;
|
||||
QList<Category> tabOrder;
|
||||
|
||||
for(const QString& name : m_object->interfaceItems().names())
|
||||
if(Property* property = m_object->getProperty(name))
|
||||
{
|
||||
Category category = property->getAttributeEnum<Category>(AttributeName::Category, Category::General);
|
||||
QWidget* w = nullptr;
|
||||
|
||||
if(property->type() == PropertyType::Boolean)
|
||||
if(property->type() == ValueType::Boolean)
|
||||
w = new PropertyCheckBox(*property);
|
||||
else if(property->type() == PropertyType::Integer)
|
||||
else if(property->type() == ValueType::Integer)
|
||||
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);
|
||||
edit->setPlaceholderText(property->displayName());
|
||||
Q_ASSERT(!tabs.contains("notes"));
|
||||
tabs.insert("notes", edit);
|
||||
Q_ASSERT(!tabs.contains(category));
|
||||
tabs.insert(category, edit);
|
||||
tabOrder.append(category);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
w = new PropertyLineEdit(*property);
|
||||
}
|
||||
else if(property->type() == PropertyType::Enum)
|
||||
else if(property->type() == ValueType::Enum)
|
||||
{
|
||||
if(property->enumName() == EnumName<Direction>::value)
|
||||
{
|
||||
@ -103,15 +122,15 @@ void ObjectEditWidget::buildForm()
|
||||
}
|
||||
|
||||
QWidget* tabWidget;
|
||||
QString tab = "general"; // TODO: get sttribute
|
||||
if(!tabs.contains(tab))
|
||||
if(!tabs.contains(category))
|
||||
{
|
||||
tabWidget = new QWidget();
|
||||
tabWidget->setLayout(new QFormLayout());
|
||||
tabs.insert(tab, tabWidget);
|
||||
tabs.insert(category, tabWidget);
|
||||
tabOrder.append(category);
|
||||
}
|
||||
else
|
||||
tabWidget = tabs[tab];
|
||||
tabWidget = tabs[category];
|
||||
|
||||
static_cast<QFormLayout*>(tabWidget->layout())->addRow(property->displayName(), w);
|
||||
}
|
||||
@ -119,8 +138,8 @@ void ObjectEditWidget::buildForm()
|
||||
if(tabs.count() > 1)
|
||||
{
|
||||
QTabWidget* tabWidget = new QTabWidget();
|
||||
for(auto it = tabs.constBegin(); it != tabs.constEnd(); it++)
|
||||
tabWidget->addTab(it.value(), it.key());
|
||||
for(Category category : tabOrder)
|
||||
tabWidget->addTab(tabs.value(category), toString(category));
|
||||
QVBoxLayout* l = new QVBoxLayout();
|
||||
l->setMargin(0);
|
||||
l->addWidget(tabWidget);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#include "../widget/alertwidget.hpp"
|
||||
|
||||
|
||||
#include "objecteditwidget.hpp"
|
||||
#include "../mainwindow.hpp"
|
||||
|
||||
ObjectListWidget::ObjectListWidget(const QString& id, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
@ -111,7 +111,7 @@ void ObjectListWidget::tableDoubleClicked(const QModelIndex& index)
|
||||
{
|
||||
const QString id = m_tableWidget->getRowObjectId(index.row());
|
||||
if(!id.isEmpty())
|
||||
(new ObjectEditWidget(id))->show();
|
||||
MainWindow::instance->showObjectEdit(id);//emit rowDoubleClicked(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -53,6 +53,9 @@ class ObjectListWidget : public QWidget
|
||||
public:
|
||||
explicit ObjectListWidget(const QString& id, QWidget* parent = nullptr);
|
||||
~ObjectListWidget() override;
|
||||
|
||||
//signals:
|
||||
// void rowDoubleClicked(const QString& id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -23,12 +23,62 @@
|
||||
#include "propertycheckbox.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) :
|
||||
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());
|
||||
connect(&m_property, &Property::valueChangedBool, this, &PropertyCheckBox::setChecked);
|
||||
connect(this, &PropertyCheckBox::toggled, &m_property, &Property::setValueBool);
|
||||
connect(&m_property, &Property::valueChangedBool,
|
||||
[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:
|
||||
Property& m_property;
|
||||
bool m_internalUpdate;
|
||||
|
||||
public:
|
||||
PropertyCheckBox(Property& property, QWidget* parent = nullptr);
|
||||
|
||||
@ -34,21 +34,36 @@ PropertyDirectionControl::PropertyDirectionControl(Property& property, QWidget*
|
||||
{
|
||||
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->setCheckable(true);
|
||||
|
||||
m_forward->setArrowType(Qt::RightArrow);
|
||||
//m_forward->setCheckable(true);
|
||||
|
||||
QHBoxLayout* l = new QHBoxLayout();
|
||||
l->addWidget(m_reverse);
|
||||
l->addWidget(m_forward);
|
||||
|
||||
setLayout(l);
|
||||
|
||||
setValue(m_property.toInt64());
|
||||
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_forward, &QToolButton::clicked, this, &PropertyDirectionControl::buttonClicked);
|
||||
}
|
||||
|
||||
@ -27,8 +27,27 @@ PropertyLineEdit::PropertyLineEdit(Property& property, QWidget* parent) :
|
||||
QLineEdit(parent),
|
||||
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());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -27,9 +27,28 @@ PropertySpinBox::PropertySpinBox(AbstractProperty& property, QWidget* parent) :
|
||||
QSpinBox(parent),
|
||||
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());
|
||||
setValue(m_property.toInt());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -27,8 +27,25 @@ PropertyTextEdit::PropertyTextEdit(Property& property, QWidget* parent) :
|
||||
QTextEdit(parent),
|
||||
m_property{property}
|
||||
{
|
||||
Q_ASSERT(m_property.type() == PropertyType::String);
|
||||
Q_ASSERT(m_property.type() == ValueType::String);
|
||||
setPlainText(m_property.toString());
|
||||
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()); });
|
||||
}
|
||||
|
||||
@ -43,7 +43,8 @@ SOURCES += \
|
||||
src/widget/propertylineedit.cpp \
|
||||
src/widget/propertyspinbox.cpp \
|
||||
src/widget/propertydirectioncontrol.cpp \
|
||||
src/widget/propertytextedit.cpp
|
||||
src/widget/propertytextedit.cpp \
|
||||
src/subwindow/objecteditsubwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/mainwindow.hpp \
|
||||
@ -77,7 +78,8 @@ HEADERS += \
|
||||
src/widget/propertylineedit.hpp \
|
||||
src/widget/propertyspinbox.hpp \
|
||||
src/widget/propertydirectioncontrol.hpp \
|
||||
src/widget/propertytextedit.hpp
|
||||
src/widget/propertytextedit.hpp \
|
||||
src/subwindow/objecteditsubwindow.hpp
|
||||
|
||||
RESOURCES += \
|
||||
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;
|
||||
|
||||
m_object.propertyChanged(m_object, *this);
|
||||
m_object.propertyChanged(*this);
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
#define SERVER_CORE_ABSTRACTPROPERTY_HPP
|
||||
|
||||
#include "interfaceitem.hpp"
|
||||
#include <enum/propertytype.hpp>
|
||||
#include <enum/valuetype.hpp>
|
||||
#include "propertyflags.hpp"
|
||||
#include "objectptr.hpp"
|
||||
#include <cassert>
|
||||
@ -33,18 +33,18 @@
|
||||
class AbstractProperty : public InterfaceItem
|
||||
{
|
||||
protected:
|
||||
const PropertyType m_type;
|
||||
const ValueType m_type;
|
||||
PropertyFlags m_flags;
|
||||
|
||||
void changed();
|
||||
|
||||
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},
|
||||
m_type{type},
|
||||
m_flags{flags}
|
||||
{
|
||||
assert(type != PropertyType::Invalid);
|
||||
assert(type != ValueType::Invalid);
|
||||
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);
|
||||
}
|
||||
|
||||
PropertyType type() const
|
||||
ValueType type() const
|
||||
{
|
||||
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;
|
||||
}}
|
||||
{
|
||||
m_interfaceItems.add(id);
|
||||
m_interfaceItems.add(id)
|
||||
.addAttributeEnabled(false);
|
||||
}
|
||||
|
||||
IdObject::~IdObject()
|
||||
@ -50,3 +51,8 @@ void IdObject::addToWorld()
|
||||
if(auto world = m_world.lock())
|
||||
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 "property.hpp"
|
||||
#include <enum/traintasticmode.hpp>
|
||||
|
||||
#define CREATE(T) \
|
||||
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);
|
||||
void addToWorld();
|
||||
void modeChanged(TraintasticMode mode) override;
|
||||
|
||||
public:
|
||||
Property<std::string> id;
|
||||
|
||||
@ -23,15 +23,36 @@
|
||||
#ifndef SERVER_CORE_INTERFACEITEM_HPP
|
||||
#define SERVER_CORE_INTERFACEITEM_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "attribute.hpp"
|
||||
#include <enum/category.hpp>
|
||||
|
||||
class Object;
|
||||
|
||||
class InterfaceItem
|
||||
{
|
||||
public:
|
||||
using Attributes = std::unordered_map<AttributeName, std::unique_ptr<AbstractAttribute>>;
|
||||
|
||||
protected:
|
||||
Object& m_object;
|
||||
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:
|
||||
InterfaceItem(Object& object, const std::string& name) :
|
||||
@ -53,6 +74,17 @@ class InterfaceItem
|
||||
{
|
||||
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
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include "interfaceitems.hpp"
|
||||
#include "interfaceitem.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void InterfaceItems::add(InterfaceItem& item)
|
||||
InterfaceItem& InterfaceItems::add(InterfaceItem& item)
|
||||
{
|
||||
m_items.emplace(item.name(), item);
|
||||
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; }
|
||||
|
||||
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); }
|
||||
};
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "objectptr.hpp"
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include "interfaceitems.hpp"
|
||||
#include <enum/traintasticmode.hpp>
|
||||
|
||||
#define CLASS_ID(id) \
|
||||
public: \
|
||||
@ -34,17 +35,23 @@
|
||||
|
||||
class AbstractMethod;
|
||||
class AbstractProperty;
|
||||
class AbstractAttribute;
|
||||
|
||||
class Object : public std::enable_shared_from_this<Object>
|
||||
{
|
||||
friend class World;
|
||||
|
||||
protected:
|
||||
InterfaceItems m_interfaceItems;
|
||||
|
||||
//void log(LogLevel level, const std::string& message) const;
|
||||
//inline void logError(const std::string& message) const { log(LogLevel::Error, message); }
|
||||
|
||||
virtual void modeChanged(TraintasticMode) {}
|
||||
|
||||
public:
|
||||
boost::signals2::signal<void (Object& object, AbstractProperty&)> propertyChanged;
|
||||
boost::signals2::signal<void (AbstractProperty&)> propertyChanged;
|
||||
boost::signals2::signal<void (AbstractAttribute&)> attributeChanged;
|
||||
|
||||
Object();
|
||||
virtual ~Object();
|
||||
|
||||
@ -39,7 +39,7 @@ class ObjectProperty : public AbstractProperty
|
||||
|
||||
public:
|
||||
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}
|
||||
{
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
#define SERVER_CORE_PROPERTY_HPP
|
||||
|
||||
#include "abstractproperty.hpp"
|
||||
#include "propertytypetraits.hpp"
|
||||
#include "valuetypetraits.hpp"
|
||||
#include "to.hpp"
|
||||
#include <functional>
|
||||
#include <enum/enum.hpp>
|
||||
@ -43,7 +43,7 @@ class Property : public AbstractProperty
|
||||
|
||||
public:
|
||||
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}
|
||||
{
|
||||
//static_assert(property_type<T>::value != PropertyType::Invalid);
|
||||
@ -90,6 +90,15 @@ class Property : public AbstractProperty
|
||||
throw invalid_value_error();
|
||||
}
|
||||
|
||||
void setValueInternal(T value)
|
||||
{
|
||||
if(m_value != value)
|
||||
{
|
||||
m_value = value;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
operator const T&() const
|
||||
{
|
||||
return m_value;
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "traintastic.hpp"
|
||||
#include "client.hpp"
|
||||
#include "abstractproperty.hpp"
|
||||
#include "abstractattribute.hpp"
|
||||
#include <enum/interfaceitemtype.hpp>
|
||||
#include "tablemodel.hpp"
|
||||
#include "world.hpp"
|
||||
@ -162,6 +163,8 @@ bool Session::processMessage(const Message& message)
|
||||
Handle handle = message.read<Handle>();
|
||||
Traintastic::instance->console->debug(m_client->m_id, "ReleaseObject: " + std::to_string(handle));
|
||||
m_handles.removeHandle(handle);
|
||||
m_propertyChanged.erase(handle);
|
||||
m_attributeChanged.erase(handle);
|
||||
break;
|
||||
}
|
||||
case Message::Command::ObjectSetProperty:
|
||||
@ -172,21 +175,21 @@ bool Session::processMessage(const Message& message)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(message.read<PropertyType>())
|
||||
switch(message.read<ValueType>())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
case ValueType::Boolean:
|
||||
property->fromBool(message.read<bool>());
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
case ValueType::Integer:
|
||||
property->fromInt64(message.read<int64_t>());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
case ValueType::Float:
|
||||
property->fromDouble(message.read<double>());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
case ValueType::String:
|
||||
property->fromString(message.read<std::string>());
|
||||
break;
|
||||
}
|
||||
@ -194,7 +197,7 @@ bool Session::processMessage(const Message& message)
|
||||
catch(const std::exception&)
|
||||
{
|
||||
// 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);
|
||||
|
||||
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(object->getClassId());
|
||||
@ -261,28 +265,28 @@ void Session::writeObject(Message& message, const ObjectPtr& object)
|
||||
message.write(property->type());
|
||||
switch(property->type())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
case ValueType::Boolean:
|
||||
message.write(property->toBool());
|
||||
break;
|
||||
|
||||
case PropertyType::Enum:
|
||||
case ValueType::Enum:
|
||||
message.write(property->toInt64());
|
||||
message.write(property->enumName());
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
case ValueType::Integer:
|
||||
message.write(property->toInt64());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
case ValueType::Float:
|
||||
message.write(property->toDouble());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
case ValueType::String:
|
||||
message.write(property->toString());
|
||||
break;
|
||||
|
||||
case PropertyType::Object:
|
||||
case ValueType::Object:
|
||||
{
|
||||
ObjectPtr obj = property->toObject();
|
||||
// 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 items
|
||||
@ -322,32 +361,63 @@ void Session::writeTableModel(Message& message, const TableModelPtr& model)
|
||||
message.writeBlockEnd(); // end model
|
||||
}
|
||||
|
||||
void Session::objectPropertyChanged(Object& object, AbstractProperty& property)
|
||||
void Session::objectPropertyChanged(AbstractProperty& property)
|
||||
{
|
||||
std::cout << "objectPropertyChanged " << property.name() << std::endl;
|
||||
|
||||
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.type());
|
||||
switch(property.type())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
case ValueType::Boolean:
|
||||
event->write(property.toBool());
|
||||
break;
|
||||
|
||||
case PropertyType::Enum:
|
||||
case PropertyType::Integer:
|
||||
case ValueType::Enum:
|
||||
case ValueType::Integer:
|
||||
event->write(property.toInt64());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
case ValueType::Float:
|
||||
event->write(property.toDouble());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
case ValueType::String:
|
||||
event->write(property.toString());
|
||||
break;
|
||||
}
|
||||
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 AbstractProperty;
|
||||
class AbstractAttribute;
|
||||
|
||||
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;
|
||||
Handles m_handles;
|
||||
std::unordered_map<Handle, boost::signals2::connection> m_propertyChanged;
|
||||
std::unordered_map<Handle, boost::signals2::connection> m_attributeChanged;
|
||||
|
||||
bool processMessage(const Message& message);
|
||||
|
||||
void writeObject(Message& message, const ObjectPtr& object);
|
||||
void writeTableModel(Message& message, const TableModelPtr& model);
|
||||
|
||||
void objectPropertyChanged(Object& object, AbstractProperty& property);
|
||||
void objectPropertyChanged(AbstractProperty& property);
|
||||
void objectAttributeChanged(AbstractAttribute& attribute);
|
||||
|
||||
public:
|
||||
Session(const std::shared_ptr<Client>& client);
|
||||
|
||||
@ -50,7 +50,7 @@ Traintastic::Traintastic(const std::filesystem::path& dataDir) :
|
||||
{
|
||||
assert(world);
|
||||
console->info(id, "Mode changed to <TODO> " + std::to_string((int)value));
|
||||
//world->modeChanged(value);
|
||||
world->modeChanged(value);
|
||||
},
|
||||
[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.
|
||||
*
|
||||
@ -20,22 +20,25 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
||||
#define SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
||||
#ifndef SERVER_CORE_VALUETYPETRAITS_HPP
|
||||
#define SERVER_CORE_VALUETYPETRAITS_HPP
|
||||
|
||||
#include <enum/propertytype.hpp>
|
||||
#include <enum/valuetype.hpp>
|
||||
#include "objectptr.hpp"
|
||||
|
||||
template<typename T>
|
||||
struct property_type
|
||||
struct value_type
|
||||
{
|
||||
static constexpr PropertyType value =
|
||||
std::is_same<T, bool>::value ? PropertyType::Boolean : (
|
||||
std::is_enum<T>::value ? PropertyType::Enum : (
|
||||
std::is_integral<T>::value ? PropertyType::Integer : (
|
||||
std::is_floating_point<T>::value ? PropertyType::Float : (
|
||||
std::is_same<T, std::string>::value ? PropertyType::String : (
|
||||
PropertyType::Invalid)))));
|
||||
static constexpr ValueType value =
|
||||
std::is_same_v<T, bool> ? ValueType::Boolean : (
|
||||
std::is_enum_v<T> ? ValueType::Enum : (
|
||||
std::is_integral_v<T> ? ValueType::Integer : (
|
||||
std::is_floating_point_v<T> ? ValueType::Float : (
|
||||
std::is_same_v<T, std::string> ? ValueType::String : (
|
||||
ValueType::Invalid)))));
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr ValueType value_type_v = value_type<T>::value;
|
||||
|
||||
#endif
|
||||
@ -103,6 +103,14 @@ ObjectPtr World::getObject(const std::string& _id) const
|
||||
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()
|
||||
{
|
||||
std::ifstream file(m_filename);
|
||||
@ -218,7 +226,7 @@ void World::save()
|
||||
for(auto& item : object->interfaceItems())
|
||||
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()))
|
||||
objectData[property->name()] = idObject->id.toJSON();
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
class World : public Object
|
||||
{
|
||||
friend class IdObject;
|
||||
friend class Traintastic;
|
||||
|
||||
protected:
|
||||
static const std::string id;
|
||||
@ -47,6 +48,7 @@ class World : public Object
|
||||
boost::uuids::uuid m_uuid;
|
||||
std::unordered_map<std::string, std::weak_ptr<Object>> m_objects;
|
||||
|
||||
void modeChanged(TraintasticMode mode);
|
||||
void load();
|
||||
|
||||
public:
|
||||
|
||||
@ -40,7 +40,8 @@ CommandStation::CommandStation(const std::weak_ptr<World>& world, const std::str
|
||||
m_interfaceItems.add(online);
|
||||
m_interfaceItems.add(status);
|
||||
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
|
||||
|
||||
@ -39,14 +39,16 @@
|
||||
#define Z21_LAN_X_UNKNOWN_COMMAND 0x82
|
||||
#define Z21_LAN_X_BC_STOPPED 0x81
|
||||
#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_GETDATA 0x85
|
||||
|
||||
#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_SMARTRAIL 0x00000202 //!< SmartRail (from 2012)
|
||||
#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_SMALL 0x00000203 //!< „white z21” starter set variant (from 2013)
|
||||
#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_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));
|
||||
|
||||
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
|
||||
{
|
||||
uint8_t addressHigh;
|
||||
@ -197,6 +216,29 @@ struct z21_lan_systemstate_getdata : z21_lan_header
|
||||
} __attribute__((packed));
|
||||
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
|
||||
{
|
||||
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()},
|
||||
hostname{this, "hostname", "", 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},
|
||||
firmwareVersion{this, "firmware_version", "", PropertyFlags::AccessRRR},
|
||||
emergencyStop{this, "emergency_stop", false, PropertyFlags::TODO,
|
||||
[this](bool value)
|
||||
{
|
||||
if(value)
|
||||
if(online && value)
|
||||
send(z21_lan_x_set_stop());
|
||||
}},
|
||||
trackVoltageOff{this, "track_voltage_off", false, PropertyFlags::TODO,
|
||||
[this](bool value)
|
||||
{
|
||||
if(online)
|
||||
{
|
||||
if(value)
|
||||
send(z21_lan_x_set_track_power_off());
|
||||
else
|
||||
send(z21_lan_x_set_track_power_on());
|
||||
}
|
||||
}}
|
||||
{
|
||||
name = "Z21";
|
||||
|
||||
m_interfaceItems.add(hostname);
|
||||
m_interfaceItems.add(port);
|
||||
m_interfaceItems.add(serialNumber);
|
||||
m_interfaceItems.add(hardwareType);
|
||||
m_interfaceItems.add(firmwareVersion);
|
||||
m_interfaceItems.add(emergencyStop);
|
||||
m_interfaceItems.add(trackVoltageOff);
|
||||
m_interfaceItems.insertBefore(hostname, notes)
|
||||
.addAttributeEnabled(true);
|
||||
m_interfaceItems.insertBefore(port, notes)
|
||||
.addAttributeEnabled(true);
|
||||
m_interfaceItems.insertBefore(serialNumber, notes)
|
||||
.addAttributeCategory(Category::Info);
|
||||
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
|
||||
@ -194,13 +204,41 @@ bool Z21::setOnline(bool& value)
|
||||
Traintastic::instance->console->error(id, "socket.bind: " + ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
receive();
|
||||
|
||||
send(z21_lan_set_broadcastflags(/*0x00010000 |*/ 0x00000100 | 0x00000001));
|
||||
|
||||
// try to communicate with Z21
|
||||
send(z21_lan_get_broadcastflags());
|
||||
send(z21_lan_get_serial_number());
|
||||
send(z21_lan_get_hwinfo());
|
||||
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)
|
||||
{
|
||||
send(z21_lan_logoff());
|
||||
|
||||
serialNumber = "";
|
||||
hardwareType = "";
|
||||
firmwareVersion = "";
|
||||
|
||||
hostname.setAttributeEnabled(true);
|
||||
port.setAttributeEnabled(true);
|
||||
emergencyStop.setAttributeEnabled(false);
|
||||
trackVoltageOff.setAttributeEnabled(false);
|
||||
|
||||
m_socket.close();
|
||||
}
|
||||
return true;
|
||||
@ -221,9 +259,9 @@ void Z21::receive()
|
||||
case Z21_LAN_GET_SERIAL_NUMBER:
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -243,10 +281,10 @@ void Z21::receive()
|
||||
case Z21_HWT_SMARTRAIL:
|
||||
hwType = "SmartRail (from 2012)";
|
||||
break;
|
||||
case Z21_HWT_z21_SMALL:
|
||||
case Z21_HWT_Z21_SMALL:
|
||||
hwType = "White Z21 (starter set variant from 2013)";
|
||||
break;
|
||||
case Z21_HWT_z21_START :
|
||||
case Z21_HWT_Z21_START :
|
||||
hwType = "Z21 start (starter set variant from 2016)";
|
||||
break;
|
||||
default:
|
||||
@ -259,8 +297,8 @@ void Z21::receive()
|
||||
EventLoop::call(
|
||||
[this, hwType, fwVersion]()
|
||||
{
|
||||
hardwareType = hwType;
|
||||
firmwareVersion = fwVersion;
|
||||
hardwareType.setValueInternal(hwType);
|
||||
firmwareVersion.setValueInternal(fwVersion);
|
||||
});
|
||||
break;
|
||||
}
|
||||
@ -294,13 +332,13 @@ void Z21::receive()
|
||||
if((speedStepMode == 0 && decoder->speedSteps == 14) ||
|
||||
(speedStepMode == 2 && decoder->speedSteps == 28) ||
|
||||
(speedStepMode == 4 && decoder->speedSteps == 126))
|
||||
decoder->speedStep = speedStep;
|
||||
decoder->speedStep.setValueInternal(speedStep);
|
||||
|
||||
for(auto& function : *decoder->functions)
|
||||
{
|
||||
const uint8_t number = function->number;
|
||||
if(number <= 28)
|
||||
function->value = functions & (1 << number);
|
||||
function->value.setValueInternal(functions & (1 << number));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -315,7 +353,7 @@ void Z21::receive()
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
{
|
||||
emergencyStop = true;
|
||||
emergencyStop.setValueInternal(true);
|
||||
});
|
||||
break;
|
||||
|
||||
@ -331,8 +369,8 @@ void Z21::receive()
|
||||
EventLoop::call(
|
||||
[this, state]()
|
||||
{
|
||||
emergencyStop = state.centralState & Z21_CENTRALSTATE_EMERGENCYSTOP;
|
||||
trackVoltageOff = state.centralState & Z21_CENTRALSTATE_TRACKVOLTAGEOFF;
|
||||
emergencyStop.setValueInternal(state.centralState & Z21_CENTRALSTATE_EMERGENCYSTOP);
|
||||
trackVoltageOff.setValueInternal(state.centralState & Z21_CENTRALSTATE_TRACKVOLTAGEOFF);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ class Z21 : public CommandStation
|
||||
|
||||
Property<std::string> hostname;
|
||||
Property<uint16_t> port;
|
||||
Property<uint32_t> serialNumber;
|
||||
Property<std::string> serialNumber;
|
||||
Property<std::string> hardwareType;
|
||||
Property<std::string> firmwareVersion;
|
||||
Property<bool> emergencyStop;
|
||||
|
||||
@ -81,13 +81,20 @@ Decoder::Decoder(const std::weak_ptr<World>& world, const std::string& _id) :
|
||||
notes{this, "notes", "", PropertyFlags::AccessWWW}
|
||||
{
|
||||
m_interfaceItems.add(name);
|
||||
m_interfaceItems.add(commandStation);
|
||||
m_interfaceItems.add(protocol);
|
||||
m_interfaceItems.add(address);
|
||||
m_interfaceItems.add(emergencyStop);
|
||||
m_interfaceItems.add(direction);
|
||||
m_interfaceItems.add(speedSteps);
|
||||
m_interfaceItems.add(speedStep);
|
||||
m_interfaceItems.add(commandStation)
|
||||
.addAttributeEnabled(false);
|
||||
m_interfaceItems.add(protocol)
|
||||
.addAttributeEnabled(false);
|
||||
m_interfaceItems.add(address)
|
||||
.addAttributeEnabled(false);
|
||||
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(notes);
|
||||
}
|
||||
@ -101,6 +108,20 @@ const std::shared_ptr<DecoderFunction>& Decoder::getFunction(uint32_t number) co
|
||||
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)
|
||||
{
|
||||
if(commandStation)
|
||||
|
||||
@ -46,6 +46,7 @@ class Decoder : public IdObject
|
||||
friend class DecoderFunction;
|
||||
|
||||
protected:
|
||||
void modeChanged(TraintasticMode mode) final;
|
||||
void changed(DecoderChangeFlags changes, uint32_t functionNumber = 0);
|
||||
|
||||
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.
|
||||
*
|
||||
@ -20,12 +20,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SHARED_ENUM_PROPERTYTYPE_HPP
|
||||
#define SHARED_ENUM_PROPERTYTYPE_HPP
|
||||
#ifndef SHARED_ENUM_VALUETYPE_HPP
|
||||
#define SHARED_ENUM_VALUETYPE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class PropertyType : uint8_t
|
||||
enum class ValueType : uint8_t
|
||||
{
|
||||
Invalid = 0,
|
||||
Boolean = 1,
|
||||
@ -59,12 +59,14 @@ class Message
|
||||
ReleaseObject = 15,
|
||||
ObjectSetProperty = 16,
|
||||
ObjectPropertyChanged = 17,
|
||||
GetTableModel = 18,
|
||||
ReleaseTableModel = 19,
|
||||
TableModelColumnHeadersChanged = 20,
|
||||
TableModelRowCountChanged = 21,
|
||||
TableModelSetRegion = 22,
|
||||
TableModelUpdateRegion = 23,
|
||||
ObjectAttributeChanged = 18,
|
||||
|
||||
GetTableModel = 19,
|
||||
ReleaseTableModel = 20,
|
||||
TableModelColumnHeadersChanged = 21,
|
||||
TableModelRowCountChanged = 22,
|
||||
TableModelSetRegion = 23,
|
||||
TableModelUpdateRegion = 24,
|
||||
|
||||
Discover = 255,
|
||||
};
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren