added (loconet) input monitor
Dieser Commit ist enthalten in:
Ursprung
90fb2ecaf8
Commit
914914a68d
@ -304,7 +304,7 @@ void MainWindow::worldChanged()
|
||||
if(m_connection)
|
||||
m_world = m_connection->world();
|
||||
else
|
||||
m_world.clear();
|
||||
m_world.reset();
|
||||
|
||||
if(m_world)
|
||||
{
|
||||
@ -416,11 +416,14 @@ void MainWindow::showObjectEdit(const ObjectPtr& object)
|
||||
*/
|
||||
void MainWindow::showObject(const ObjectPtr& object)
|
||||
{
|
||||
const QString& id = object->getProperty("id")->toString();
|
||||
if(!m_mdiSubWindows.contains(id))
|
||||
QString id;
|
||||
if(auto* property = object->getProperty("id"))
|
||||
id = property->toString();
|
||||
if(id.isEmpty() || !m_mdiSubWindows.contains(id))
|
||||
{
|
||||
QMdiSubWindow* window = new ObjectSubWindow(object);
|
||||
m_mdiSubWindows[id] = window;
|
||||
if(!id.isEmpty())
|
||||
m_mdiSubWindows[id] = window;
|
||||
m_mdiArea->addSubWindow(window);
|
||||
window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(window, &QMdiSubWindow::destroyed, this,
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "objectproperty.hpp"
|
||||
#include "method.hpp"
|
||||
#include "tablemodel.hpp"
|
||||
#include "inputmonitor.hpp"
|
||||
#include <traintastic/enum/interfaceitemtype.hpp>
|
||||
#include <traintastic/enum/attributetype.hpp>
|
||||
#include <traintastic/locale/locale.hpp>
|
||||
@ -299,6 +300,37 @@ void Connection::setTableModelRegion(TableModel* tableModel, int columnMin, int
|
||||
send(event);
|
||||
}
|
||||
|
||||
int Connection::getInputMonitorInputInfo(InputMonitor& inputMonitor)
|
||||
{
|
||||
auto request = Message::newRequest(Message::Command::InputMonitorGetInputInfo);
|
||||
request->write(inputMonitor.handle());
|
||||
send(request,
|
||||
[&inputMonitor](const std::shared_ptr<Message> message)
|
||||
{
|
||||
uint32_t count = message->read<uint32_t>();
|
||||
while(count > 0)
|
||||
{
|
||||
const uint32_t address = message->read<uint32_t>();
|
||||
const QString id = QString::fromUtf8(message->read<QByteArray>());
|
||||
const TriState value = message->read<TriState>();
|
||||
emit inputMonitor.inputIdChanged(address, id);
|
||||
emit inputMonitor.inputValueChanged(address, value);
|
||||
count--;
|
||||
}
|
||||
|
||||
/*
|
||||
TableModelPtr tableModel;
|
||||
if(!message->isError())
|
||||
{
|
||||
tableModel = readTableModel(*message);
|
||||
m_tableModels[tableModel->handle()] = tableModel.data();
|
||||
}
|
||||
callback(tableModel, message->errorCode());
|
||||
*/
|
||||
});
|
||||
return request->requestId();
|
||||
}
|
||||
|
||||
void Connection::send(std::unique_ptr<Message>& message)
|
||||
{
|
||||
Q_ASSERT(!message->isRequest());
|
||||
@ -323,7 +355,10 @@ ObjectPtr Connection::readObject(const Message& message)
|
||||
if(!obj)
|
||||
{
|
||||
const QString classId = QString::fromLatin1(message.read<QByteArray>());
|
||||
obj = QSharedPointer<Object>::create(sharedFromThis(), handle, classId);
|
||||
if(classId.startsWith(InputMonitor::classIdPrefix))
|
||||
obj = std::make_shared<InputMonitor>(sharedFromThis(), handle, classId);
|
||||
else
|
||||
obj = std::make_shared<Object>(sharedFromThis(), handle, classId);
|
||||
m_objects[handle] = obj;
|
||||
|
||||
message.readBlock(); // items
|
||||
@ -806,6 +841,24 @@ void Connection::processMessage(const std::shared_ptr<Message> message)
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::InputMonitorInputIdChanged:
|
||||
if(auto inputMonitor = std::dynamic_pointer_cast<InputMonitor>(m_objects.value(message->read<Handle>()).lock()))
|
||||
{
|
||||
const uint32_t address = message->read<uint32_t>();
|
||||
const QString id = QString::fromUtf8(message->read<QByteArray>());
|
||||
emit inputMonitor->inputIdChanged(address, id);
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::InputMonitorInputValueChanged:
|
||||
if(auto inputMonitor = std::dynamic_pointer_cast<InputMonitor>(m_objects.value(message->read<Handle>()).lock()))
|
||||
{
|
||||
const uint32_t address = message->read<uint32_t>();
|
||||
const TriState value = message->read<TriState>();
|
||||
emit inputMonitor->inputValueChanged(address, value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
|
||||
@ -37,6 +37,7 @@ class Property;
|
||||
class ObjectProperty;
|
||||
class UnitProperty;
|
||||
class Method;
|
||||
class InputMonitor;
|
||||
|
||||
class Connection : public QObject, public QEnableSharedFromThis<Connection>
|
||||
{
|
||||
@ -73,7 +74,7 @@ class Connection : public QObject, public QEnableSharedFromThis<Connection>
|
||||
ObjectProperty* m_worldProperty;
|
||||
int m_worldRequestId;
|
||||
ObjectPtr m_world;
|
||||
QMap<Handle, QWeakPointer<Object>> m_objects;
|
||||
QMap<Handle, std::weak_ptr<Object>> m_objects;
|
||||
QMap<Handle, TableModel*> m_tableModels;
|
||||
|
||||
void setState(State state);
|
||||
@ -138,6 +139,8 @@ class Connection : public QObject, public QEnableSharedFromThis<Connection>
|
||||
void releaseTableModel(TableModel* tableModel);
|
||||
void setTableModelRegion(TableModel* tableModel, int columnMin, int columnMax, int rowMin, int rowMax);
|
||||
|
||||
[[nodiscard]] int getInputMonitorInputInfo(InputMonitor& object);
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
void worldChanged();
|
||||
|
||||
43
client/src/network/inputmonitor.cpp
Normale Datei
43
client/src/network/inputmonitor.cpp
Normale Datei
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* client/src/network/inputmonitor.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "inputmonitor.hpp"
|
||||
#include "connection.hpp"
|
||||
|
||||
InputMonitor::InputMonitor(const QSharedPointer<Connection>& connection, Handle handle, const QString& classId) :
|
||||
Object(connection, handle, classId),
|
||||
m_requestId{Connection::invalidRequestId}
|
||||
{
|
||||
}
|
||||
|
||||
InputMonitor::~InputMonitor()
|
||||
{
|
||||
if(m_requestId != Connection::invalidRequestId)
|
||||
m_connection->cancelRequest(m_requestId);
|
||||
}
|
||||
|
||||
void InputMonitor::refresh()
|
||||
{
|
||||
if(m_requestId != Connection::invalidRequestId)
|
||||
m_connection->cancelRequest(m_requestId);
|
||||
m_requestId = m_connection->getInputMonitorInputInfo(*this);
|
||||
}
|
||||
49
client/src/network/inputmonitor.hpp
Normale Datei
49
client/src/network/inputmonitor.hpp
Normale Datei
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* client/src/network/inputmonitor.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_CLIENT_NETWORK_INPUTMONITOR_HPP
|
||||
#define TRAINTASTIC_CLIENT_NETWORK_INPUTMONITOR_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
#include <traintastic/enum/tristate.hpp>
|
||||
|
||||
class InputMonitor final : public Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
int m_requestId;
|
||||
|
||||
public:
|
||||
inline static const QString classIdPrefix = QStringLiteral("input_monitor.");
|
||||
|
||||
InputMonitor(const QSharedPointer<Connection>& connection, Handle handle, const QString& classId);
|
||||
~InputMonitor() final;
|
||||
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void inputIdChanged(uint32_t address, QString id);
|
||||
void inputValueChanged(uint32_t address, TriState value);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -46,8 +46,8 @@ class Object : public QObject
|
||||
|
||||
public:
|
||||
explicit Object(const QSharedPointer<Connection>& connection, Handle handle, const QString& classId);
|
||||
Object(const Object& copy) = delete;
|
||||
~Object() final;
|
||||
Object(const Object&) = delete;
|
||||
~Object() override;
|
||||
|
||||
const QSharedPointer<Connection>& connection() const { return m_connection; }
|
||||
Handle handle() const { return m_handle; }
|
||||
|
||||
@ -23,10 +23,10 @@
|
||||
#ifndef TRAINTASTIC_CLIENT_NETWORK_OBJECTPTR_HPP
|
||||
#define TRAINTASTIC_CLIENT_NETWORK_OBJECTPTR_HPP
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <memory>
|
||||
|
||||
class Object;
|
||||
|
||||
using ObjectPtr = QSharedPointer<Object>;
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
|
||||
#endif
|
||||
|
||||
@ -28,7 +28,9 @@
|
||||
#include "luascriptlistwidget.hpp"
|
||||
#include "object/luascripteditwidget.hpp"
|
||||
#include "object/objecteditwidget.hpp"
|
||||
#include "inputmonitorwidget.hpp"
|
||||
#include "../network/object.hpp"
|
||||
#include "../network/inputmonitor.hpp"
|
||||
|
||||
QWidget* createWidgetIfCustom(const ObjectPtr& object, QWidget* parent)
|
||||
{
|
||||
@ -62,6 +64,8 @@ QWidget* createWidget(const ObjectPtr& object, QWidget* parent)
|
||||
return widget;
|
||||
else if(object->classId().startsWith("list."))
|
||||
return new ObjectListWidget(object, parent);
|
||||
else if(auto inputMonitor = std::dynamic_pointer_cast<InputMonitor>(object))
|
||||
return new InputMonitorWidget(inputMonitor, parent);
|
||||
else
|
||||
return new ObjectEditWidget(object, parent);
|
||||
}
|
||||
|
||||
80
client/src/widget/inputmonitorwidget.cpp
Normale Datei
80
client/src/widget/inputmonitorwidget.cpp
Normale Datei
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* client/src/widget/inputmonitorwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "inputmonitorwidget.hpp"
|
||||
#include <QGridLayout>
|
||||
#include "ledwidget.hpp"
|
||||
#include "../network/inputmonitor.hpp"
|
||||
|
||||
constexpr LEDWidget::State toState(TriState value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case TriState::False:
|
||||
return LEDWidget::State::Off;
|
||||
case TriState::True:
|
||||
return LEDWidget::State::On;
|
||||
case TriState::Undefined:
|
||||
break;
|
||||
}
|
||||
return LEDWidget::State::Undefined;
|
||||
}
|
||||
|
||||
|
||||
InputMonitorWidget::InputMonitorWidget(std::shared_ptr<InputMonitor> object, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_object{std::move(object)}
|
||||
{
|
||||
QGridLayout* grid = new QGridLayout();
|
||||
|
||||
for(int i = 1; i <= 128; i++)
|
||||
{
|
||||
auto* led = new LEDWidget(this);
|
||||
led->setEnabled(false);
|
||||
led->setText(QString::number(i));
|
||||
grid->addWidget(led, (i - 1) / 16, (i - 1) % 16);
|
||||
m_leds.emplace(i, led);
|
||||
}
|
||||
|
||||
setLayout(grid);
|
||||
|
||||
connect(m_object.get(), &InputMonitor::inputIdChanged, this,
|
||||
[this](uint32_t address, QString id)
|
||||
{
|
||||
if(auto* led = getLED(address))
|
||||
led->setEnabled(!id.isEmpty());
|
||||
});
|
||||
connect(m_object.get(), &InputMonitor::inputValueChanged, this,
|
||||
[this](uint32_t address, TriState value)
|
||||
{
|
||||
if(auto* led = getLED(address))
|
||||
led->setState(toState(value));
|
||||
});
|
||||
|
||||
m_object->refresh();
|
||||
}
|
||||
|
||||
LEDWidget* InputMonitorWidget::getLED(uint32_t address)
|
||||
{
|
||||
auto it = m_leds.find(address);
|
||||
return it != m_leds.end() ? it->second : nullptr;
|
||||
}
|
||||
45
client/src/widget/inputmonitorwidget.hpp
Normale Datei
45
client/src/widget/inputmonitorwidget.hpp
Normale Datei
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* client/src/widget/inputmonitorwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_CLIENT_WIDGET_INPUTMONITORWIDGET_HPP
|
||||
#define TRAINTASTIC_CLIENT_WIDGET_INPUTMONITORWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
class InputMonitor;
|
||||
class LEDWidget;
|
||||
|
||||
class InputMonitorWidget : public QWidget
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<InputMonitor> m_object;
|
||||
std::unordered_map<uint32_t, LEDWidget*> m_leds;
|
||||
|
||||
LEDWidget* getLED(uint32_t address);
|
||||
|
||||
public:
|
||||
InputMonitorWidget(std::shared_ptr<InputMonitor> object, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
103
client/src/widget/ledwidget.cpp
Normale Datei
103
client/src/widget/ledwidget.cpp
Normale Datei
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* client/src/widget/ledwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "ledwidget.hpp"
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
LEDWidget::LEDWidget(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_enabled{true},
|
||||
m_state{State::Undefined}
|
||||
{
|
||||
setMinimumWidth(fontMetrics().averageCharWidth() * 4);
|
||||
setMinimumHeight((fontMetrics().height() * 3) / 2);
|
||||
}
|
||||
|
||||
void LEDWidget::setEnabled(bool value)
|
||||
{
|
||||
if(m_enabled != value)
|
||||
{
|
||||
m_enabled = value;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void LEDWidget::setState(State value)
|
||||
{
|
||||
if(m_state != value)
|
||||
{
|
||||
m_state = value;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void LEDWidget::setText(const QString& value)
|
||||
{
|
||||
if(m_text != value)
|
||||
{
|
||||
m_text = value;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void LEDWidget::paintEvent(QPaintEvent*)
|
||||
{
|
||||
const int marginV = (height() - minimumHeight()) / 2;
|
||||
const int ledHeight = minimumHeight() / 3;
|
||||
const int ledWidth = fontMetrics().averageCharWidth() * 3;
|
||||
const int ledLeft = (width() - ledWidth) / 2;
|
||||
const int ledRadius = ledHeight / 2;
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
if(!m_text.isEmpty())
|
||||
{
|
||||
const QRect textRect = rect().adjusted(0, marginV + minimumHeight() / 2, 0, -marginV);
|
||||
painter.setPen(palette().color(m_enabled ? QPalette::Normal : QPalette::Disabled, QPalette::WindowText));
|
||||
painter.drawText(textRect, Qt::AlignCenter | Qt::AlignBaseline, m_text);
|
||||
}
|
||||
|
||||
const QRect ledRect{ledLeft, marginV + 1, ledWidth, ledHeight};// = rect().adjusted(0, marginV, 0, -(marginV + minimumHeight() / 2));
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(ledRect, ledRadius, ledRadius);
|
||||
switch(m_state)
|
||||
{
|
||||
case State::Undefined:
|
||||
break;
|
||||
|
||||
case State::Off:
|
||||
painter.fillPath(path, QColor(0x20, 0x20, 0x20));//painter.fillPath(path, QColor(0x70, 0x80, 0x90));
|
||||
break;
|
||||
|
||||
case State::On:
|
||||
painter.fillPath(path, QColor(0x00, 0xBF, 0xFF));
|
||||
break;
|
||||
}
|
||||
|
||||
QPen pen = painter.pen();
|
||||
pen.setColor(Qt::black);
|
||||
pen.setWidth(2);
|
||||
painter.setPen(pen);
|
||||
painter.drawPath(path);
|
||||
}
|
||||
57
client/src/widget/ledwidget.hpp
Normale Datei
57
client/src/widget/ledwidget.hpp
Normale Datei
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* client/src/widget/ledwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_CLIENT_WIDGET_LEDWIDGET_HPP
|
||||
#define TRAINTASTIC_CLIENT_WIDGET_LEDWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class LEDWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Undefined,
|
||||
Off,
|
||||
On,
|
||||
};
|
||||
|
||||
protected:
|
||||
bool m_enabled;
|
||||
State m_state;
|
||||
QString m_text;
|
||||
|
||||
void paintEvent(QPaintEvent*) final;
|
||||
|
||||
public:
|
||||
explicit LEDWidget(QWidget *parent = nullptr);
|
||||
|
||||
bool enabled() const { return m_enabled; }
|
||||
void setEnabled(bool value);
|
||||
|
||||
State state() const { return m_state; }
|
||||
void setState(State value);
|
||||
|
||||
QString text() const { return m_text; }
|
||||
void setText(const QString& value);
|
||||
};
|
||||
|
||||
#endif
|
||||
76
client/src/widget/methodpushbutton.cpp
Normale Datei
76
client/src/widget/methodpushbutton.cpp
Normale Datei
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* client/src/widget/methodpushbutton.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "methodpushbutton.hpp"
|
||||
#include "../network/connection.hpp"
|
||||
#include "../network/method.hpp"
|
||||
#include "../mainwindow.hpp"
|
||||
|
||||
MethodPushButton::MethodPushButton(Method& method, QWidget* parent) :
|
||||
QPushButton(parent),
|
||||
m_method{method},
|
||||
m_requestId{Connection::invalidRequestId}
|
||||
{
|
||||
setEnabled(m_method.getAttributeBool(AttributeName::Enabled, true));
|
||||
setVisible(m_method.getAttributeBool(AttributeName::Visible, true));
|
||||
connect(&m_method, &Method::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, &MethodPushButton::clicked,
|
||||
[this]()
|
||||
{
|
||||
if(m_method.argumentTypes().count() == 0)
|
||||
switch(m_method.resultType())
|
||||
{
|
||||
case ValueType::Invalid:
|
||||
m_method.call();
|
||||
break;
|
||||
|
||||
case ValueType::Object:
|
||||
m_requestId = m_method.call(
|
||||
[this](const ObjectPtr& object, Message::ErrorCode)
|
||||
{
|
||||
if(object)
|
||||
MainWindow::instance->showObject(object);
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
40
client/src/widget/methodpushbutton.hpp
Normale Datei
40
client/src/widget/methodpushbutton.hpp
Normale Datei
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* client/src/widget/methodpushbutton.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_CLIENT_WIDGET_METHODPUSHBUTTON_HPP
|
||||
#define TRAINTASTIC_CLIENT_WIDGET_METHODPUSHBUTTON_HPP
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
class Method;
|
||||
|
||||
class MethodPushButton : public QPushButton
|
||||
{
|
||||
protected:
|
||||
Method& m_method;
|
||||
int m_requestId;
|
||||
|
||||
public:
|
||||
MethodPushButton(Method& method, QWidget* parent);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -31,6 +31,7 @@
|
||||
#include "../../network/property.hpp"
|
||||
#include "../../network/objectproperty.hpp"
|
||||
#include "../../network/unitproperty.hpp"
|
||||
#include "../../network/method.hpp"
|
||||
//#include "../../network/utils.hpp"
|
||||
//#include "../alertwidget.hpp"
|
||||
#include "../propertycheckbox.hpp"
|
||||
@ -41,6 +42,7 @@
|
||||
#include "../propertyobjectedit.hpp"
|
||||
#include "../propertydirectioncontrol.hpp"
|
||||
#include "../propertyvaluelabel.hpp"
|
||||
#include "../methodpushbutton.hpp"
|
||||
#include "../unitpropertyedit.hpp"
|
||||
#include "../createwidget.hpp"
|
||||
#include "../../utils/geticonforclassid.hpp"
|
||||
@ -90,70 +92,77 @@ void ObjectEditWidget::buildForm()
|
||||
|
||||
for(const QString& name : m_object->interfaceItems().names())
|
||||
{
|
||||
if(AbstractProperty* baseProperty = m_object->getProperty(name))
|
||||
if(InterfaceItem* item = m_object->getInterfaceItem(name))
|
||||
{
|
||||
if(!baseProperty->getAttributeBool(AttributeName::ObjectEditor, true))
|
||||
continue;
|
||||
|
||||
QWidget* w = nullptr;
|
||||
|
||||
if(baseProperty->type() == ValueType::Object)
|
||||
if(AbstractProperty* baseProperty = dynamic_cast<AbstractProperty*>(item))
|
||||
{
|
||||
ObjectProperty* property = static_cast<ObjectProperty*>(baseProperty);
|
||||
if(contains(baseProperty->flags(), PropertyFlags::SubObject))
|
||||
{
|
||||
QWidget* w = new ObjectEditWidget(property->objectId());
|
||||
w->setWindowTitle(property->displayName());
|
||||
tabs.append(w);
|
||||
if(!baseProperty->getAttributeBool(AttributeName::ObjectEditor, true))
|
||||
continue;
|
||||
|
||||
if(baseProperty->type() == ValueType::Object)
|
||||
{
|
||||
ObjectProperty* property = static_cast<ObjectProperty*>(baseProperty);
|
||||
if(contains(baseProperty->flags(), PropertyFlags::SubObject))
|
||||
{
|
||||
QWidget* w = new ObjectEditWidget(property->objectId());
|
||||
w->setWindowTitle(property->displayName());
|
||||
tabs.append(w);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
w = new PropertyObjectEdit(*property);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w = new PropertyObjectEdit(*property);
|
||||
Property* property = static_cast<Property*>(baseProperty);
|
||||
if(UnitProperty* unitProperty = dynamic_cast<UnitProperty*>(property))
|
||||
w = new UnitPropertyEdit(*unitProperty);
|
||||
else if(!property->isWritable())
|
||||
w = new PropertyValueLabel(*property);
|
||||
else if(property->type() == ValueType::Boolean)
|
||||
w = new PropertyCheckBox(*property);
|
||||
else if(property->type() == ValueType::Integer)
|
||||
w = new PropertySpinBox(*property);
|
||||
else if(property->type() == ValueType::String)
|
||||
{
|
||||
if(property->name() == "notes")
|
||||
{
|
||||
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
||||
edit->setWindowTitle(property->displayName());
|
||||
edit->setPlaceholderText(property->displayName());
|
||||
tabs.append(edit);
|
||||
continue;
|
||||
}
|
||||
else if(property->name() == "code")
|
||||
{
|
||||
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
||||
edit->setWindowTitle(property->displayName());
|
||||
edit->setPlaceholderText(property->displayName());
|
||||
tabs.append(edit);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
w = new PropertyLineEdit(*property);
|
||||
}
|
||||
else if(property->type() == ValueType::Enum)
|
||||
{
|
||||
if(property->enumName() == EnumName<Direction>::value)
|
||||
w = new PropertyDirectionControl(*property);
|
||||
else
|
||||
w = new PropertyComboBox(*property);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(Method* method = dynamic_cast<Method*>(item))
|
||||
{
|
||||
Property* property = static_cast<Property*>(baseProperty);
|
||||
if(UnitProperty* unitProperty = dynamic_cast<UnitProperty*>(property))
|
||||
w = new UnitPropertyEdit(*unitProperty);
|
||||
else if(!property->isWritable())
|
||||
w = new PropertyValueLabel(*property);
|
||||
else if(property->type() == ValueType::Boolean)
|
||||
w = new PropertyCheckBox(*property);
|
||||
else if(property->type() == ValueType::Integer)
|
||||
w = new PropertySpinBox(*property);
|
||||
else if(property->type() == ValueType::String)
|
||||
{
|
||||
if(property->name() == "notes")
|
||||
{
|
||||
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
||||
edit->setWindowTitle(property->displayName());
|
||||
edit->setPlaceholderText(property->displayName());
|
||||
tabs.append(edit);
|
||||
continue;
|
||||
}
|
||||
else if(property->name() == "code")
|
||||
{
|
||||
PropertyTextEdit* edit = new PropertyTextEdit(*property);
|
||||
edit->setWindowTitle(property->displayName());
|
||||
edit->setPlaceholderText(property->displayName());
|
||||
tabs.append(edit);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
w = new PropertyLineEdit(*property);
|
||||
}
|
||||
else if(property->type() == ValueType::Enum)
|
||||
{
|
||||
if(property->enumName() == EnumName<Direction>::value)
|
||||
w = new PropertyDirectionControl(*property);
|
||||
else
|
||||
w = new PropertyComboBox(*property);
|
||||
}
|
||||
w = new MethodPushButton(*method, this);
|
||||
}
|
||||
|
||||
Category category = baseProperty->getAttributeEnum<Category>(AttributeName::Category, Category::General);
|
||||
Category category = item->getAttributeEnum<Category>(AttributeName::Category, Category::General);
|
||||
QWidget* tabWidget;
|
||||
if(!categoryTabs.contains(category))
|
||||
{
|
||||
@ -166,7 +175,7 @@ void ObjectEditWidget::buildForm()
|
||||
else
|
||||
tabWidget = categoryTabs[category];
|
||||
|
||||
static_cast<QFormLayout*>(tabWidget->layout())->addRow(baseProperty->displayName(), w);
|
||||
static_cast<QFormLayout*>(tabWidget->layout())->addRow(item->displayName(), w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ SOURCES += \
|
||||
src/main.cpp \
|
||||
src/mainwindow.cpp \
|
||||
src/dialog/connectdialog.cpp \
|
||||
src/network/inputmonitor.cpp \
|
||||
src/network/object.cpp \
|
||||
../shared/src/traintastic/locale/locale.cpp \
|
||||
src/network/unitproperty.cpp \
|
||||
@ -63,11 +64,15 @@ SOURCES += \
|
||||
src/utils/geticonforclassid.cpp \
|
||||
src/widget/propertyobjectedit.cpp \
|
||||
src/utils/enum.cpp \
|
||||
src/dialog/objectselectlistdialog.cpp
|
||||
src/dialog/objectselectlistdialog.cpp \
|
||||
src/widget/inputmonitorwidget.cpp \
|
||||
src/widget/ledwidget.cpp \
|
||||
src/widget/methodpushbutton.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/mainwindow.hpp \
|
||||
src/dialog/connectdialog.hpp \
|
||||
src/network/inputmonitor.hpp \
|
||||
src/network/object.hpp \
|
||||
../shared/src/traintastic/message.hpp \
|
||||
../shared/src/traintastic/locale/locale.hpp \
|
||||
@ -117,7 +122,10 @@ HEADERS += \
|
||||
src/utils/geticonforclassid.hpp \
|
||||
src/widget/propertyobjectedit.hpp \
|
||||
src/utils/enum.hpp \
|
||||
src/dialog/objectselectlistdialog.hpp
|
||||
src/dialog/objectselectlistdialog.hpp \
|
||||
src/widget/inputmonitorwidget.hpp \
|
||||
src/widget/ledwidget.hpp \
|
||||
src/widget/methodpushbutton.hpp
|
||||
|
||||
RESOURCES += \
|
||||
dark.qrc
|
||||
|
||||
@ -53,6 +53,13 @@ struct Attributes
|
||||
item.setAttribute(AttributeName::Enabled, value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline void addMinMax(Property<T>& property, T min, T max)
|
||||
{
|
||||
property.addAttribute(AttributeName::Min, min);
|
||||
property.addAttribute(AttributeName::Max, max);
|
||||
}
|
||||
|
||||
static inline void addVisible(InterfaceItem& item, bool value)
|
||||
{
|
||||
item.addAttribute(AttributeName::Visible, value);
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
#include "abstractobjectlist.hpp"
|
||||
#include "idobject.hpp"
|
||||
#include "subobject.hpp"
|
||||
|
||||
template<typename T>
|
||||
class ObjectListTableModel;
|
||||
@ -34,7 +35,7 @@ class ObjectList : public AbstractObjectList
|
||||
{
|
||||
friend class ObjectListTableModel<T>;
|
||||
|
||||
static_assert(std::is_base_of<IdObject, T>::value);
|
||||
static_assert(std::is_base_of_v<IdObject, T> || std::is_base_of_v<SubObject, T>);
|
||||
|
||||
public:
|
||||
using Items = std::vector<std::shared_ptr<T>>;
|
||||
|
||||
@ -115,7 +115,7 @@ class ObjectProperty : public AbstractObjectProperty
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
inline operator bool()
|
||||
inline operator bool() const
|
||||
{
|
||||
return m_value.operator bool();
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include "../world/world.hpp"
|
||||
#include "idobject.hpp"
|
||||
#include "subobject.hpp"
|
||||
#include "../hardware/input/inputmonitor.hpp"
|
||||
|
||||
|
||||
|
||||
@ -194,7 +195,22 @@ bool Session::processMessage(const Message& message)
|
||||
const std::string id = message.read<std::string>();
|
||||
if(!id.empty())
|
||||
{
|
||||
if(ObjectPtr value = Traintastic::instance->world->getObject(id))
|
||||
// TODO: move to function??
|
||||
std::vector<std::string> ids;
|
||||
boost::split(ids, id, [](char c){ return c == '.'; });
|
||||
auto it = ids.cbegin();
|
||||
|
||||
ObjectPtr value = Traintastic::instance->world->getObject(*it);
|
||||
while(value && ++it != ids.cend())
|
||||
{
|
||||
AbstractProperty* property = value->getProperty(*it);
|
||||
if(property && property->type() == ValueType::Object)
|
||||
value = property->toObject();
|
||||
else
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
if(value)
|
||||
property->fromObject(value);
|
||||
else
|
||||
throw std::runtime_error("");
|
||||
@ -376,6 +392,24 @@ bool Session::processMessage(const Message& message)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Message::Command::InputMonitorGetInputInfo:
|
||||
{
|
||||
auto inputMonitor = std::dynamic_pointer_cast<InputMonitor>(m_handles.getItem(message.read<Handle>()));
|
||||
if(inputMonitor)
|
||||
{
|
||||
auto inputInfo = inputMonitor->getInputInfo();
|
||||
auto response = Message::newResponse(message.command(), message.requestId());
|
||||
response->write<uint32_t>(inputInfo.size());
|
||||
for(auto& info : inputInfo)
|
||||
{
|
||||
response->write(info.address);
|
||||
response->write(info.id);
|
||||
response->write(info.value);
|
||||
}
|
||||
m_client->sendMessage(std::move(response));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -396,6 +430,12 @@ void Session::writeObject(Message& message, const ObjectPtr& object)
|
||||
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)));
|
||||
|
||||
if(auto* inputMonitor = dynamic_cast<InputMonitor*>(object.get()))
|
||||
{
|
||||
inputMonitor->inputIdChanged = std::bind(&Session::inputMonitorInputIdChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
inputMonitor->inputValueChanged = std::bind(&Session::inputMonitorInputValueChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
}
|
||||
|
||||
message.write(handle);
|
||||
message.write(object->getClassId());
|
||||
|
||||
@ -657,3 +697,21 @@ void Session::writeAttribute(Message& message , const AbstractAttribute& attribu
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
void Session::inputMonitorInputIdChanged(InputMonitor& inputMonitor, uint32_t address, const std::string& id)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::InputMonitorInputIdChanged);
|
||||
event->write(m_handles.getHandle(inputMonitor.shared_from_this()));
|
||||
event->write(address);
|
||||
event->write(id);
|
||||
m_client->sendMessage(std::move(event));
|
||||
}
|
||||
|
||||
void Session::inputMonitorInputValueChanged(InputMonitor& inputMonitor, uint32_t address, TriState value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::InputMonitorInputValueChanged);
|
||||
event->write(m_handles.getHandle(inputMonitor.shared_from_this()));
|
||||
event->write(address);
|
||||
event->write(value);
|
||||
m_client->sendMessage(std::move(event));
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/signals2/connection.hpp>
|
||||
#include <traintastic/network/message.hpp>
|
||||
#include <traintastic/enum/tristate.hpp>
|
||||
#include "handlelist.hpp"
|
||||
#include "objectptr.hpp"
|
||||
#include "tablemodelptr.hpp"
|
||||
@ -34,6 +35,7 @@
|
||||
class Client;
|
||||
class AbstractProperty;
|
||||
class AbstractAttribute;
|
||||
class InputMonitor;
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session>
|
||||
{
|
||||
@ -60,6 +62,9 @@ class Session : public std::enable_shared_from_this<Session>
|
||||
void objectPropertyChanged(AbstractProperty& property);
|
||||
void objectAttributeChanged(AbstractAttribute& attribute);
|
||||
|
||||
void inputMonitorInputIdChanged(InputMonitor& inputMonitor, uint32_t address, const std::string& id);
|
||||
void inputMonitorInputValueChanged(InputMonitor& inputMonitor, uint32_t address, TriState value);
|
||||
|
||||
public:
|
||||
Session(const std::shared_ptr<Client>& client);
|
||||
|
||||
|
||||
@ -40,9 +40,9 @@ class TableModel : public Object
|
||||
|
||||
|
||||
Region() :
|
||||
columnMin{0},
|
||||
columnMin{1},
|
||||
columnMax{0},
|
||||
rowMin{0},
|
||||
rowMin{1},
|
||||
rowMax{0}
|
||||
{
|
||||
}
|
||||
@ -77,6 +77,11 @@ class TableModel : public Object
|
||||
this->rowMin >= rhs.rowMin &&
|
||||
this->rowMax <= rhs.rowMax;
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return columnMax >= columnMin && rowMax >= rowMin;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
34
server/src/enum/tristate.hpp
Normale Datei
34
server/src/enum/tristate.hpp
Normale Datei
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* server/src/enum/tristate.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_ENUM_TRISTATE_HPP
|
||||
#define TRAINTASTIC_SERVER_ENUM_TRISTATE_HPP
|
||||
|
||||
#include <traintastic/enum/tristate.hpp>
|
||||
|
||||
inline constexpr std::array<TriState, 3> TriStateValues{{
|
||||
TriState::Undefined,
|
||||
TriState::False,
|
||||
TriState::True,
|
||||
}};
|
||||
|
||||
#endif
|
||||
@ -49,7 +49,7 @@ LocoNetSerial::LocoNetSerial(const std::weak_ptr<World>& world, std::string_view
|
||||
loconet{this, "loconet", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
|
||||
{
|
||||
name = "LocoNet (serial)";
|
||||
loconet.setValueInternal(std::make_shared<LocoNet::LocoNet>(*this, loconet.name(), std::bind(&LocoNetSerial::send, this, std::placeholders::_1)));
|
||||
loconet.setValueInternal(LocoNet::LocoNet::create(*this, loconet.name(), std::bind(&LocoNetSerial::send, this, std::placeholders::_1)));
|
||||
|
||||
Attributes::addEnabled(interface, !online);
|
||||
Attributes::addValues(interface, LocoNetSerialInterfaceValues);
|
||||
|
||||
@ -82,7 +82,7 @@ RocoZ21::RocoZ21(const std::weak_ptr<World>& world, std::string_view _id) :
|
||||
shortCircutExternal{this, "short_circut_external", false, PropertyFlags::ReadOnly}
|
||||
{
|
||||
name = "Z21";
|
||||
loconet.setValueInternal(std::make_shared<LocoNet::LocoNet>(*this, loconet.name(),
|
||||
loconet.setValueInternal(LocoNet::LocoNet::create(*this, loconet.name(),
|
||||
[/*this*/](const ::LocoNet::Message& /*msg*/)
|
||||
{
|
||||
return false;
|
||||
|
||||
@ -23,13 +23,19 @@
|
||||
#include "input.hpp"
|
||||
#include "../../world/world.hpp"
|
||||
#include "inputlisttablemodel.hpp"
|
||||
#include "../../core/attributes.hpp"
|
||||
|
||||
Input::Input(const std::weak_ptr<World> world, std::string_view _id) :
|
||||
IdObject(world, _id),
|
||||
name{this, "name", "", PropertyFlags::ReadWrite | PropertyFlags::Store},
|
||||
value{this, "value", false, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
value{this, "value", TriState::Undefined, PropertyFlags::ReadOnly | PropertyFlags::StoreState}
|
||||
{
|
||||
auto w = world.lock();
|
||||
const bool editable = w && contains(w->state.value(), WorldState::Edit);
|
||||
|
||||
Attributes::addEnabled(name, editable);
|
||||
m_interfaceItems.add(name);
|
||||
Attributes::addValues(value, TriStateValues);
|
||||
m_interfaceItems.add(value);
|
||||
}
|
||||
|
||||
@ -41,7 +47,16 @@ void Input::addToWorld()
|
||||
world->inputs->addObject(shared_ptr<Input>());
|
||||
}
|
||||
|
||||
void Input::valueChanged(bool _value)
|
||||
void Input::worldEvent(WorldState state, WorldEvent event)
|
||||
{
|
||||
IdObject::worldEvent(state, event);
|
||||
|
||||
const bool editable = contains(state, WorldState::Edit);
|
||||
|
||||
name.setAttributeEnabled(editable);
|
||||
}
|
||||
|
||||
void Input::valueChanged(TriState _value)
|
||||
{
|
||||
// todo: delay in ms for 0->1 || 1->0
|
||||
value.setValueInternal(_value);
|
||||
|
||||
@ -24,17 +24,19 @@
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUT_HPP
|
||||
|
||||
#include "../../core/idobject.hpp"
|
||||
#include "../../enum/tristate.hpp"
|
||||
|
||||
class Input : public IdObject
|
||||
{
|
||||
protected:
|
||||
void addToWorld() override;
|
||||
void worldEvent(WorldState state, WorldEvent event) override;
|
||||
|
||||
void valueChanged(bool _value);
|
||||
void valueChanged(TriState _value);
|
||||
|
||||
public:
|
||||
Property<std::string> name;
|
||||
Property<bool> value;
|
||||
Property<TriState> value;
|
||||
|
||||
Input(const std::weak_ptr<World> world, std::string_view _id);
|
||||
};
|
||||
|
||||
@ -22,10 +22,27 @@
|
||||
|
||||
#include "inputlist.hpp"
|
||||
#include "inputlisttablemodel.hpp"
|
||||
#include "inputs.hpp"
|
||||
#include "../../world/getworld.hpp"
|
||||
#include "../../core/attributes.hpp"
|
||||
|
||||
InputList::InputList(Object& _parent, const std::string& parentPropertyName) :
|
||||
ObjectList<Input>(_parent, parentPropertyName)
|
||||
ObjectList<Input>(_parent, parentPropertyName),
|
||||
add{*this, "add",
|
||||
[this](std::string_view classId)
|
||||
{
|
||||
auto world = getWorld(&this->parent());
|
||||
if(!world)
|
||||
return std::shared_ptr<Input>();
|
||||
return Inputs::create(world, classId, world->getUniqueId("input"));
|
||||
}}
|
||||
{
|
||||
auto w = getWorld(&_parent);
|
||||
const bool editable = w && contains(w->state.value(), WorldState::Edit);
|
||||
|
||||
Attributes::addEnabled(add, editable);
|
||||
Attributes::addClassList(add, Inputs::classList);
|
||||
m_interfaceItems.add(add);
|
||||
}
|
||||
|
||||
TableModelPtr InputList::getModel()
|
||||
@ -33,6 +50,15 @@ TableModelPtr InputList::getModel()
|
||||
return std::make_shared<InputListTableModel>(*this);
|
||||
}
|
||||
|
||||
void InputList::worldEvent(WorldState state, WorldEvent event)
|
||||
{
|
||||
ObjectList<Input>::worldEvent(state, event);
|
||||
|
||||
const bool editable = contains(state, WorldState::Edit);
|
||||
|
||||
add.setAttributeEnabled(editable);
|
||||
}
|
||||
|
||||
bool InputList::isListedProperty(const std::string& name)
|
||||
{
|
||||
return InputListTableModel::isListedProperty(name);
|
||||
|
||||
@ -24,17 +24,21 @@
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUTLIST_HPP
|
||||
|
||||
#include "../../core/objectlist.hpp"
|
||||
#include "../../core/method.hpp"
|
||||
#include "inputlist.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
class InputList : public ObjectList<Input>
|
||||
{
|
||||
protected:
|
||||
void worldEvent(WorldState state, WorldEvent event) final;
|
||||
bool isListedProperty(const std::string& name) final;
|
||||
|
||||
public:
|
||||
CLASS_ID("input_list")
|
||||
|
||||
Method<std::shared_ptr<Input>(std::string_view)> add;
|
||||
|
||||
InputList(Object& _parent, const std::string& parentPropertyName);
|
||||
|
||||
TableModelPtr getModel() final;
|
||||
|
||||
@ -22,23 +22,24 @@
|
||||
|
||||
#include "inputlisttablemodel.hpp"
|
||||
#include "inputlist.hpp"
|
||||
#include "loconetinput.hpp"
|
||||
|
||||
constexpr uint32_t columnId = 0;
|
||||
constexpr uint32_t columnName = 1;
|
||||
constexpr uint32_t columnValue = 2;
|
||||
constexpr uint32_t columnBus = 2;
|
||||
constexpr uint32_t columnAddress = 3;
|
||||
|
||||
bool InputListTableModel::isListedProperty(const std::string& name)
|
||||
{
|
||||
return
|
||||
name == "id" ||
|
||||
name == "name" ||
|
||||
name == "value";
|
||||
name == "name";
|
||||
}
|
||||
|
||||
InputListTableModel::InputListTableModel(InputList& list) :
|
||||
ObjectListTableModel<Input>(list)
|
||||
{
|
||||
setColumnHeaders({"Id", "Name", "Value"});
|
||||
setColumnHeaders({"Id", "Name", "input_list:bus", "input_list:address"});
|
||||
}
|
||||
|
||||
std::string InputListTableModel::getText(uint32_t column, uint32_t row) const
|
||||
@ -46,6 +47,7 @@ std::string InputListTableModel::getText(uint32_t column, uint32_t row) const
|
||||
if(row < rowCount())
|
||||
{
|
||||
const Input& input = getItem(row);
|
||||
const LocoNetInput* inputLocoNet = dynamic_cast<const LocoNetInput*>(&input);
|
||||
|
||||
switch(column)
|
||||
{
|
||||
@ -55,8 +57,17 @@ std::string InputListTableModel::getText(uint32_t column, uint32_t row) const
|
||||
case columnName:
|
||||
return input.name;
|
||||
|
||||
case columnValue:
|
||||
return input.value ? "1" : "0";
|
||||
case columnBus: // virtual method @ Input ??
|
||||
if(inputLocoNet && inputLocoNet->loconet)
|
||||
return inputLocoNet->loconet->getObjectId();
|
||||
else
|
||||
return "";
|
||||
|
||||
case columnAddress: // virtual method @ Input ??
|
||||
if(inputLocoNet)
|
||||
return std::to_string(inputLocoNet->address);
|
||||
else
|
||||
return "";
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
@ -73,6 +84,4 @@ void InputListTableModel::propertyChanged(AbstractProperty& property, uint32_t r
|
||||
changed(row, columnId);
|
||||
else if(property.name() == "name")
|
||||
changed(row, columnName);
|
||||
else if(property.name() == "value")
|
||||
changed(row, columnValue);
|
||||
}
|
||||
|
||||
64
server/src/hardware/input/inputmonitor.hpp
Normale Datei
64
server/src/hardware/input/inputmonitor.hpp
Normale Datei
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* server/src/hardware/input/inputmonitor.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUTMONITOR_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUTMONITOR_HPP
|
||||
|
||||
#include "../../core/object.hpp"
|
||||
#include <vector>
|
||||
#include "../../core/property.hpp"
|
||||
#include "../../enum/tristate.hpp"
|
||||
|
||||
class InputMonitor : public Object
|
||||
{
|
||||
public:
|
||||
std::function<void(InputMonitor&, uint32_t, const std::string&)> inputIdChanged;
|
||||
std::function<void(InputMonitor&, uint32_t, TriState)> inputValueChanged;
|
||||
|
||||
struct InputInfo
|
||||
{
|
||||
uint32_t address;
|
||||
std::string id;
|
||||
TriState value;
|
||||
|
||||
InputInfo(uint32_t _address, std::string _id, TriState _value) :
|
||||
address{_address},
|
||||
id{std::move(_id)},
|
||||
value{_value}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Property<uint32_t> addressMin;
|
||||
Property<uint32_t> addressMax;
|
||||
|
||||
InputMonitor() :
|
||||
Object(),
|
||||
addressMin{this, "address_min", 0, PropertyFlags::ReadOnly | PropertyFlags::NoStore},
|
||||
addressMax{this, "address_max", 0, PropertyFlags::ReadOnly | PropertyFlags::NoStore}
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::vector<InputInfo> getInputInfo() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
31
server/src/hardware/input/inputs.cpp
Normale Datei
31
server/src/hardware/input/inputs.cpp
Normale Datei
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* server/src/hardware/input/inputs.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "inputs.hpp"
|
||||
|
||||
std::shared_ptr<Input> Inputs::create(const std::weak_ptr<World>& world, std::string_view classId, std::string_view id)
|
||||
{
|
||||
if(classId == LocoNetInput::classId)
|
||||
return LocoNetInput::create(world, id);
|
||||
else
|
||||
return std::shared_ptr<Input>();
|
||||
}
|
||||
42
server/src/hardware/input/inputs.hpp
Normale Datei
42
server/src/hardware/input/inputs.hpp
Normale Datei
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* server/src/hardware/input/inputs.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUTS_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INPUT_INPUTS_HPP
|
||||
|
||||
#include "input.hpp"
|
||||
#include "../../utils/makearray.hpp"
|
||||
|
||||
#include "loconetinput.hpp"
|
||||
|
||||
struct Inputs
|
||||
{
|
||||
static constexpr std::string_view classIdPrefix = "input.";
|
||||
|
||||
static constexpr auto classList = makeArray(
|
||||
LocoNetInput::classId
|
||||
);
|
||||
|
||||
static std::shared_ptr<Input> create(const std::weak_ptr<World>& world, std::string_view classId, std::string_view id);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include "loconetinput.hpp"
|
||||
#include "../../core/attributes.hpp"
|
||||
#include "../../world/world.hpp"
|
||||
|
||||
LocoNetInput::LocoNetInput(const std::weak_ptr<World> world, std::string_view _id) :
|
||||
Input(world, _id),
|
||||
@ -36,18 +37,23 @@ LocoNetInput::LocoNetInput(const std::weak_ptr<World> world, std::string_view _i
|
||||
}
|
||||
return false;
|
||||
}},
|
||||
address{this, "address", 0, PropertyFlags::ReadWrite | PropertyFlags::Store, nullptr,
|
||||
address{this, "address", addressMin, PropertyFlags::ReadWrite | PropertyFlags::Store, nullptr,
|
||||
[this](const uint16_t& value)
|
||||
{
|
||||
if(loconet)
|
||||
return loconet->isInputAddressAvailable(value);
|
||||
return loconet->changeInputAddress(*this, value);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}}
|
||||
{
|
||||
Attributes::addEnabled(loconet, false);
|
||||
auto w = world.lock();
|
||||
const bool editable = w && contains(w->state.value(), WorldState::Edit);
|
||||
|
||||
Attributes::addEnabled(loconet, editable);
|
||||
Attributes::addObjectList(loconet, w->loconets);
|
||||
m_interfaceItems.add(loconet);
|
||||
Attributes::addEnabled(address, false);
|
||||
Attributes::addEnabled(address, editable);
|
||||
Attributes::addMinMax(address, addressMin, addressMax);
|
||||
m_interfaceItems.add(address);
|
||||
}
|
||||
|
||||
|
||||
@ -34,12 +34,15 @@ class LocoNetInput : public Input
|
||||
protected:
|
||||
void worldEvent(WorldState state, WorldEvent event) final;
|
||||
|
||||
inline void valueChanged(bool _value) { Input::valueChanged(_value); }
|
||||
inline void valueChanged(TriState _value) { Input::valueChanged(_value); }
|
||||
|
||||
public:
|
||||
CLASS_ID("input.loconet")
|
||||
CREATE(LocoNetInput)
|
||||
|
||||
static constexpr uint16_t addressMin = 1;
|
||||
static constexpr uint16_t addressMax = 4096;
|
||||
|
||||
ObjectProperty<LocoNet::LocoNet> loconet;
|
||||
Property<uint16_t> address;
|
||||
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
#include "../../commandstation/commandstation.hpp"
|
||||
#include "../../input/loconetinput.hpp"
|
||||
#include "../../../core/attributes.hpp"
|
||||
#include "../../../world/getworld.hpp"
|
||||
#include "loconetlisttablemodel.hpp"
|
||||
|
||||
namespace LocoNet {
|
||||
|
||||
@ -41,7 +43,15 @@ void updateDecoderSpeed(const std::shared_ptr<Decoder>& decoder, uint8_t speed)
|
||||
decoder->speedStep.setValueInternal(((speed - 1) * decoder->speedSteps) / (SPEED_MAX - 1));
|
||||
}
|
||||
|
||||
LocoNet::LocoNet(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send) :
|
||||
std::shared_ptr<LocoNet> LocoNet::create(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send)
|
||||
{
|
||||
std::shared_ptr<LocoNet> object{std::make_shared<LocoNet>(_parent, parentPropertyName, std::move(send), Private())};
|
||||
if(auto w = getWorld(&_parent))
|
||||
w->loconets->addObject(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
LocoNet::LocoNet(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send, Private) :
|
||||
SubObject(_parent, parentPropertyName),
|
||||
m_commandStation{dynamic_cast<CommandStation*>(&_parent)},
|
||||
m_send{std::move(send)},
|
||||
@ -66,6 +76,11 @@ LocoNet::LocoNet(Object& _parent, const std::string& parentPropertyName, std::fu
|
||||
[this](bool value)
|
||||
{
|
||||
m_debugLog = value;
|
||||
}},
|
||||
inputMonitor{*this, "input_monitor",
|
||||
[this]()
|
||||
{
|
||||
return std::make_shared<LocoNetInputMonitor>(shared_ptr<LocoNet>());
|
||||
}}
|
||||
{
|
||||
assert(m_send);
|
||||
@ -74,6 +89,7 @@ LocoNet::LocoNet(Object& _parent, const std::string& parentPropertyName, std::fu
|
||||
Attributes::addValues(commandStation, LocoNetCommandStationValues);
|
||||
m_interfaceItems.add(commandStation);
|
||||
m_interfaceItems.add(debugLog);
|
||||
m_interfaceItems.add(inputMonitor);
|
||||
}
|
||||
|
||||
bool LocoNet::send(const Message& message)
|
||||
@ -204,9 +220,14 @@ void LocoNet::receive(const Message& message)
|
||||
EventLoop::call(
|
||||
[this, inputRep=*static_cast<const InputRep*>(&message)]()
|
||||
{
|
||||
auto it = m_inputs.find(1 + inputRep.address());
|
||||
const uint16_t address = 1 + inputRep.fullAddress();
|
||||
auto it = m_inputs.find(address);
|
||||
if(it != m_inputs.end())
|
||||
it->second->valueChanged(inputRep.value());
|
||||
it->second->valueChanged(toTriState(inputRep.value()));
|
||||
|
||||
for(auto* inputMonitor : m_inputMonitors)
|
||||
if(inputMonitor->inputValueChanged)
|
||||
inputMonitor->inputValueChanged(*inputMonitor, address, toTriState(inputRep.value()));
|
||||
});
|
||||
break;
|
||||
|
||||
@ -372,14 +393,28 @@ std::shared_ptr<Decoder> LocoNet::getDecoder(uint8_t slot, bool request)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LocoNet::isInputAddressAvailable(uint16_t address)
|
||||
bool LocoNet::isInputAddressAvailable(uint16_t address) const
|
||||
{
|
||||
return m_inputs.find(address) == m_inputs.end();
|
||||
}
|
||||
|
||||
bool LocoNet::changeInputAddress(const LocoNetInput& input, uint16_t newAddress)
|
||||
{
|
||||
assert(input.loconet.value().get() == this);
|
||||
|
||||
if(!isInputAddressAvailable(newAddress))
|
||||
return false;
|
||||
|
||||
auto node = m_inputs.extract(input.address); // old address
|
||||
node.key() = newAddress;
|
||||
m_inputs.insert(std::move(node));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LocoNet::addInput(const std::shared_ptr<LocoNetInput>& input)
|
||||
{
|
||||
assert(input->loconet.value().get() == this);
|
||||
assert(input);
|
||||
if(isInputAddressAvailable(input->address))
|
||||
{
|
||||
m_inputs.insert({input->address, input});
|
||||
@ -391,7 +426,7 @@ bool LocoNet::addInput(const std::shared_ptr<LocoNetInput>& input)
|
||||
|
||||
void LocoNet::removeInput(const std::shared_ptr<LocoNetInput>& input)
|
||||
{
|
||||
assert(input->loconet.value().get() == this);
|
||||
assert(input && input->loconet.value().get() == this);
|
||||
m_inputs.erase(m_inputs.find(input->address));
|
||||
}
|
||||
|
||||
|
||||
@ -32,22 +32,31 @@
|
||||
#include <vector>
|
||||
#include "../../../core/subobject.hpp"
|
||||
#include "../../../core/property.hpp"
|
||||
#include "../../../core/method.hpp"
|
||||
#include <traintastic/enum/direction.hpp>
|
||||
#include "../../../enum/loconetcommandstation.hpp"
|
||||
//#include <cstdint>
|
||||
//#include <cassert>
|
||||
#include "../../../hardware/decoder/decoderchangeflags.hpp"
|
||||
#include "messages.hpp"
|
||||
#include "loconetinputmonitor.hpp"
|
||||
|
||||
class CommandStation;
|
||||
class Decoder;
|
||||
class LocoNetInput;
|
||||
class LocoNetInputMonitor;
|
||||
|
||||
namespace LocoNet {
|
||||
|
||||
class LocoNet : public SubObject
|
||||
{
|
||||
//friend class LocoNetInput;
|
||||
friend class ::LocoNetInputMonitor;
|
||||
|
||||
private:
|
||||
struct Private
|
||||
{
|
||||
};
|
||||
|
||||
protected:
|
||||
static constexpr bool isLongAddress(uint16_t address)
|
||||
@ -97,6 +106,7 @@ class LocoNet : public SubObject
|
||||
std::unordered_map<uint16_t, std::vector<std::byte>> m_slotRequests;
|
||||
uint8_t m_queryLocoSlots;
|
||||
std::unordered_map<uint16_t, std::shared_ptr<LocoNetInput>> m_inputs;
|
||||
std::vector<LocoNetInputMonitor*> m_inputMonitors;
|
||||
|
||||
std::shared_ptr<Decoder> getDecoder(uint8_t slot, bool request = true);
|
||||
|
||||
@ -108,7 +118,8 @@ class LocoNet : public SubObject
|
||||
}
|
||||
|
||||
public://protected:
|
||||
bool isInputAddressAvailable(uint16_t address);
|
||||
bool isInputAddressAvailable(uint16_t address) const;
|
||||
bool changeInputAddress(const LocoNetInput& input, uint16_t newAddress);
|
||||
bool addInput(const std::shared_ptr<LocoNetInput>& input);
|
||||
void removeInput(const std::shared_ptr<LocoNetInput>& input);
|
||||
|
||||
@ -117,8 +128,11 @@ class LocoNet : public SubObject
|
||||
|
||||
Property<LocoNetCommandStation> commandStation;
|
||||
Property<bool> debugLog;
|
||||
Method<std::shared_ptr<LocoNetInputMonitor>()> inputMonitor;
|
||||
|
||||
LocoNet(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send);
|
||||
static std::shared_ptr<LocoNet> create(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send);
|
||||
|
||||
LocoNet(Object& _parent, const std::string& parentPropertyName, std::function<bool(const Message&)> send, Private);
|
||||
|
||||
bool send(const Message& message);
|
||||
void receive(const Message& message);
|
||||
|
||||
52
server/src/hardware/protocol/loconet/loconetinputmonitor.cpp
Normale Datei
52
server/src/hardware/protocol/loconet/loconetinputmonitor.cpp
Normale Datei
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/loconetinputmonitor.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "loconetinputmonitor.hpp"
|
||||
#include "loconet.hpp"
|
||||
#include "../../input/loconetinput.hpp"
|
||||
|
||||
LocoNetInputMonitor::LocoNetInputMonitor(std::shared_ptr<LocoNet::LocoNet> loconet) :
|
||||
InputMonitor(),
|
||||
m_loconet{std::move(loconet)}
|
||||
{
|
||||
addressMin.setValueInternal(LocoNetInput::addressMin);
|
||||
addressMax.setValueInternal(LocoNetInput::addressMax);
|
||||
m_loconet->m_inputMonitors.emplace_back(this);
|
||||
}
|
||||
|
||||
LocoNetInputMonitor::~LocoNetInputMonitor()
|
||||
{
|
||||
if(auto it = std::find(m_loconet->m_inputMonitors.begin(), m_loconet->m_inputMonitors.end(), this); it != m_loconet->m_inputMonitors.end())
|
||||
m_loconet->m_inputMonitors.erase(it);
|
||||
}
|
||||
|
||||
std::vector<InputMonitor::InputInfo> LocoNetInputMonitor::getInputInfo() const
|
||||
{
|
||||
std::vector<InputInfo> inputInfo;
|
||||
for(auto it : m_loconet->m_inputs)
|
||||
{
|
||||
LocoNetInput& input = *(it.second);
|
||||
InputInfo info(input.address, input.id, input.value);
|
||||
inputInfo.push_back(info);
|
||||
}
|
||||
return inputInfo;
|
||||
}
|
||||
48
server/src/hardware/protocol/loconet/loconetinputmonitor.hpp
Normale Datei
48
server/src/hardware/protocol/loconet/loconetinputmonitor.hpp
Normale Datei
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/loconetinputmonitor.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETINPUTMONITOR_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETINPUTMONITOR_HPP
|
||||
|
||||
#include "../../input/inputmonitor.hpp"
|
||||
|
||||
namespace LocoNet {
|
||||
class LocoNet;
|
||||
}
|
||||
|
||||
class LocoNetInputMonitor final : public InputMonitor
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<LocoNet::LocoNet> m_loconet;
|
||||
|
||||
public:
|
||||
CLASS_ID("input_monitor.loconet")
|
||||
|
||||
LocoNetInputMonitor(std::shared_ptr<LocoNet::LocoNet> loconet);
|
||||
~LocoNetInputMonitor() final;
|
||||
|
||||
std::string getObjectId() const final { return ""; }
|
||||
|
||||
std::vector<InputInfo> getInputInfo() const final;
|
||||
};
|
||||
|
||||
#endif
|
||||
39
server/src/hardware/protocol/loconet/loconetlist.cpp
Normale Datei
39
server/src/hardware/protocol/loconet/loconetlist.cpp
Normale Datei
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/loconetlist.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "loconetlist.hpp"
|
||||
#include "loconetlisttablemodel.hpp"
|
||||
|
||||
LocoNetList::LocoNetList(Object& _parent, const std::string& parentPropertyName) :
|
||||
ObjectList<LocoNet::LocoNet>(_parent, parentPropertyName)
|
||||
{
|
||||
}
|
||||
|
||||
TableModelPtr LocoNetList::getModel()
|
||||
{
|
||||
return std::make_shared<LocoNetListTableModel>(*this);
|
||||
}
|
||||
|
||||
bool LocoNetList::isListedProperty(const std::string& name)
|
||||
{
|
||||
return LocoNetListTableModel::isListedProperty(name);
|
||||
}
|
||||
42
server/src/hardware/protocol/loconet/loconetlist.hpp
Normale Datei
42
server/src/hardware/protocol/loconet/loconetlist.hpp
Normale Datei
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/loconetlist.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETLIST_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETLIST_HPP
|
||||
|
||||
#include "../../../core/objectlist.hpp"
|
||||
#include "loconet.hpp"
|
||||
|
||||
class LocoNetList : public ObjectList<LocoNet::LocoNet>
|
||||
{
|
||||
protected:
|
||||
bool isListedProperty(const std::string& name) final;
|
||||
|
||||
public:
|
||||
CLASS_ID("loconet_list")
|
||||
|
||||
LocoNetList(Object& _parent, const std::string& parentPropertyName);
|
||||
|
||||
TableModelPtr getModel() final;
|
||||
};
|
||||
|
||||
#endif
|
||||
63
server/src/hardware/protocol/loconet/loconetlisttablemodel.cpp
Normale Datei
63
server/src/hardware/protocol/loconet/loconetlisttablemodel.cpp
Normale Datei
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* server/src/hardware/input/loconetlisttablemodel.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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.
|
||||
*/
|
||||
|
||||
#include "loconetlisttablemodel.hpp"
|
||||
#include "loconetlist.hpp"
|
||||
|
||||
constexpr uint32_t columnId = 0;
|
||||
|
||||
bool LocoNetListTableModel::isListedProperty(const std::string& name)
|
||||
{
|
||||
return name == "id";
|
||||
}
|
||||
|
||||
LocoNetListTableModel::LocoNetListTableModel(LocoNetList& list) :
|
||||
ObjectListTableModel<LocoNet::LocoNet>(list)
|
||||
{
|
||||
setColumnHeaders({"id"});
|
||||
}
|
||||
|
||||
std::string LocoNetListTableModel::getText(uint32_t column, uint32_t row) const
|
||||
{
|
||||
if(row < rowCount())
|
||||
{
|
||||
const LocoNet::LocoNet& loconet = getItem(row);
|
||||
|
||||
switch(column)
|
||||
{
|
||||
case columnId:
|
||||
return loconet.getObjectId();
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void LocoNetListTableModel::propertyChanged(AbstractProperty& property, uint32_t row)
|
||||
{
|
||||
if(property.name() == "id")
|
||||
changed(row, columnId);
|
||||
}
|
||||
48
server/src/hardware/protocol/loconet/loconetlisttablemodel.hpp
Normale Datei
48
server/src/hardware/protocol/loconet/loconetlisttablemodel.hpp
Normale Datei
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/loconetlisttablemodel.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETLISTTABLEMODEL_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_LOCONETLISTTABLEMODEL_HPP
|
||||
|
||||
#include "../../../core/objectlisttablemodel.hpp"
|
||||
#include "loconet.hpp"
|
||||
|
||||
class LocoNetList;
|
||||
|
||||
class LocoNetListTableModel : public ObjectListTableModel<LocoNet::LocoNet>
|
||||
{
|
||||
friend class LocoNetList;
|
||||
|
||||
protected:
|
||||
void propertyChanged(AbstractProperty& property, uint32_t row) final;
|
||||
|
||||
public:
|
||||
CLASS_ID("loconet_list_table_model")
|
||||
|
||||
static bool isListedProperty(const std::string& name);
|
||||
|
||||
LocoNetListTableModel(LocoNetList& list);
|
||||
|
||||
std::string getText(uint32_t column, uint32_t row) const final;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -77,31 +77,31 @@ constexpr std::string_view toString(OpCode value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case LocoNet::OPC_BUSY: return "OPC_BUSY";
|
||||
case LocoNet::OPC_GPOFF: return "OPC_GPOFFqqq";
|
||||
case LocoNet::OPC_GPON: return "OPC_GPON";
|
||||
case LocoNet::OPC_IDLE: return "OPC_IDLE";
|
||||
case LocoNet::OPC_LOCO_SPD: return "OPC_LOCO_SPD";
|
||||
case LocoNet::OPC_LOCO_DIRF: return "OPC_LOCO_DIRF";
|
||||
case LocoNet::OPC_LOCO_SND: return "OPC_LOCO_SND";
|
||||
case LocoNet::OPC_SW_REQ: return "OPC_SW_REQ";
|
||||
case LocoNet::OPC_SW_REP: return "OPC_SW_REP";
|
||||
case LocoNet::OPC_INPUT_REP: return "OPC_INPUT_REP";
|
||||
case LocoNet::OPC_LONG_ACK: return "OPC_LONG_ACK";
|
||||
case LocoNet::OPC_SLOT_STAT1: return "OPC_SLOT_STAT1";
|
||||
case LocoNet::OPC_CONSIST_FUNC: return "OPC_CONSIST_FUNC";
|
||||
case LocoNet::OPC_UNLINK_SLOTS: return "OPC_UNLINK_SLOTS";
|
||||
case LocoNet::OPC_LINK_SLOTS: return "OPC_LINK_SLOTS";
|
||||
case LocoNet::OPC_MOVE_SLOTS: return "OPC_MOVE_SLOTS";
|
||||
case LocoNet::OPC_RQ_SL_DATA: return "OPC_RQ_SL_DATA";
|
||||
case LocoNet::OPC_SW_STATE: return "OPC_SW_STATE";
|
||||
case LocoNet::OPC_SW_ACK: return "OPC_SW_ACK";
|
||||
case LocoNet::OPC_LOCO_ADR: return "OPC_LOCO_ADR";
|
||||
case LocoNet::OPC_MULTI_SENSE: return "OPC_MULTI_SENSE";
|
||||
case LocoNet::OPC_PEER_XFER: return "OPC_PEER_XFER";
|
||||
case LocoNet::OPC_SL_RD_DATA: return "OPC_SL_RD_DATA";
|
||||
case LocoNet::OPC_IMM_PACKET: return "OPC_IMM_PACKET";
|
||||
case LocoNet::OPC_WR_SL_DATA: return "OPC_WR_SL_DATA";
|
||||
case OPC_BUSY: return "OPC_BUSY";
|
||||
case OPC_GPOFF: return "OPC_GPOFFqqq";
|
||||
case OPC_GPON: return "OPC_GPON";
|
||||
case OPC_IDLE: return "OPC_IDLE";
|
||||
case OPC_LOCO_SPD: return "OPC_LOCO_SPD";
|
||||
case OPC_LOCO_DIRF: return "OPC_LOCO_DIRF";
|
||||
case OPC_LOCO_SND: return "OPC_LOCO_SND";
|
||||
case OPC_SW_REQ: return "OPC_SW_REQ";
|
||||
case OPC_SW_REP: return "OPC_SW_REP";
|
||||
case OPC_INPUT_REP: return "OPC_INPUT_REP";
|
||||
case OPC_LONG_ACK: return "OPC_LONG_ACK";
|
||||
case OPC_SLOT_STAT1: return "OPC_SLOT_STAT1";
|
||||
case OPC_CONSIST_FUNC: return "OPC_CONSIST_FUNC";
|
||||
case OPC_UNLINK_SLOTS: return "OPC_UNLINK_SLOTS";
|
||||
case OPC_LINK_SLOTS: return "OPC_LINK_SLOTS";
|
||||
case OPC_MOVE_SLOTS: return "OPC_MOVE_SLOTS";
|
||||
case OPC_RQ_SL_DATA: return "OPC_RQ_SL_DATA";
|
||||
case OPC_SW_STATE: return "OPC_SW_STATE";
|
||||
case OPC_SW_ACK: return "OPC_SW_ACK";
|
||||
case OPC_LOCO_ADR: return "OPC_LOCO_ADR";
|
||||
case OPC_MULTI_SENSE: return "OPC_MULTI_SENSE";
|
||||
case OPC_PEER_XFER: return "OPC_PEER_XFER";
|
||||
case OPC_SL_RD_DATA: return "OPC_SL_RD_DATA";
|
||||
case OPC_IMM_PACKET: return "OPC_IMM_PACKET";
|
||||
case OPC_WR_SL_DATA: return "OPC_WR_SL_DATA";
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@ -45,6 +45,7 @@ void World::init(const std::shared_ptr<World>& world)
|
||||
world->decoders.setValueInternal(std::make_shared<DecoderList>(*world, world->decoders.name()));
|
||||
world->inputs.setValueInternal(std::make_shared<InputList>(*world, world->inputs.name()));
|
||||
world->controllers.setValueInternal(std::make_shared<ControllerList>(*world, world->controllers.name()));
|
||||
world->loconets.setValueInternal(std::make_shared<LocoNetList>(*world, world->loconets.name()));
|
||||
world->clock.setValueInternal(std::make_shared<Clock>(*world, world->clock.name()));
|
||||
world->trains.setValueInternal(std::make_shared<TrainList>(*world, world->trains.name()));
|
||||
world->railVehicles.setValueInternal(std::make_shared<RailVehicleList>(*world, world->railVehicles.name()));
|
||||
@ -62,6 +63,7 @@ World::World(Private) :
|
||||
decoders{this, "decoders", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
inputs{this, "inputs", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
controllers{this, "controllers", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
loconets{this, "loconets", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
clock{this, "clock", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
trains{this, "trains", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
railVehicles{this, "rail_vehicles", nullptr, PropertyFlags::ReadOnly | PropertyFlags::SubObject},
|
||||
@ -129,6 +131,7 @@ World::World(Private) :
|
||||
m_interfaceItems.add(decoders);
|
||||
m_interfaceItems.add(inputs);
|
||||
m_interfaceItems.add(controllers);
|
||||
m_interfaceItems.add(loconets);
|
||||
m_interfaceItems.add(clock);
|
||||
m_interfaceItems.add(trains);
|
||||
m_interfaceItems.add(railVehicles);
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include "../hardware/decoder/decoderlist.hpp"
|
||||
#include "../hardware/input/inputlist.hpp"
|
||||
#include "../hardware/controller/controllerlist.hpp"
|
||||
#include "../hardware/protocol/loconet/loconetlist.hpp"
|
||||
#include "../train/trainlist.hpp"
|
||||
#include "../vehicle/rail/railvehiclelist.hpp"
|
||||
#ifndef DISABLE_LUA_SCRIPTING
|
||||
@ -81,6 +82,7 @@ class World : public Object
|
||||
ObjectProperty<DecoderList> decoders;
|
||||
ObjectProperty<InputList> inputs;
|
||||
ObjectProperty<ControllerList> controllers;
|
||||
ObjectProperty<LocoNetList> loconets;
|
||||
ObjectProperty<Clock> clock;
|
||||
ObjectProperty<TrainList> trains;
|
||||
ObjectProperty<RailVehicleList> railVehicles;
|
||||
|
||||
63
shared/src/traintastic/enum/tristate.hpp
Normale Datei
63
shared/src/traintastic/enum/tristate.hpp
Normale Datei
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* shared/src/enum/tristate.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2020 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 TRAINTASTIC_SHARED_TRAINTASTIC_ENUM_TRISTATE_HPP
|
||||
#define TRAINTASTIC_SHARED_TRAINTASTIC_ENUM_TRISTATE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include "enum.hpp"
|
||||
|
||||
enum class TriState : uint8_t
|
||||
{
|
||||
Undefined = 0,
|
||||
False = 1,
|
||||
True = 2,
|
||||
};
|
||||
|
||||
ENUM_NAME(TriState, "tri_state")
|
||||
|
||||
ENUM_VALUES(TriState, 3,
|
||||
{
|
||||
{TriState::Undefined, "undefined"},
|
||||
{TriState::False, "false"},
|
||||
{TriState::True, "true"},
|
||||
})
|
||||
|
||||
constexpr TriState toTriState(bool value)
|
||||
{
|
||||
return value ? TriState::True : TriState::False;
|
||||
}
|
||||
|
||||
constexpr TriState operator!(TriState value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case TriState::False:
|
||||
return TriState::True;
|
||||
case TriState::True:
|
||||
return TriState::False;
|
||||
default:
|
||||
return TriState::Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -71,6 +71,10 @@ class Message
|
||||
TableModelSetRegion = 23,
|
||||
TableModelUpdateRegion = 24,
|
||||
|
||||
InputMonitorGetInputInfo = 30,
|
||||
InputMonitorInputIdChanged = 31,
|
||||
InputMonitorInputValueChanged = 32,
|
||||
|
||||
Discover = 255,
|
||||
};
|
||||
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren