Loading...
Searching...
No Matches
AvndDevice.hpp
1#pragma once
2#include <State/Widgets/AddressFragmentLineEdit.hpp>
3
4#include <Explorer/DefaultProtocolFactory.hpp>
5
6#include <Crousti/Concepts.hpp>
7
8#include <ossia/network/base/protocol.hpp>
9#include <ossia/network/generic/generic_device.hpp>
10
11#include <QFormLayout>
12
13#include <avnd/concepts/generic.hpp>
14
15namespace oscr
16{
17template <typename Node>
18class Protocol final : public ossia::net::protocol_base
19{
20public:
21 explicit Protocol(const ossia::net::network_context_ptr& ctx)
22 : ossia::net::protocol_base{flags{}}
23 {
24 if_possible(this->impl.io_context = &ctx->context);
25 if_possible(this->impl.init());
26 }
27
28 template <bool Input, typename Field>
29 ossia::net::parameter_base* create_node(ossia::net::node_base& root, Field& f)
30 {
31 ossia::net::node_base* node{};
32 if constexpr(avnd::has_path<Field>)
33 {
34 static constexpr auto name = avnd::get_path<Field>();
35 node = &ossia::net::create_node(root, name);
36 }
37 else
38 {
39 static constexpr auto name = avnd::get_name<Field>();
40 if constexpr(Input)
41 {
42 node = &ossia::net::create_node(root, fmt::format("/in/{}", name));
43 }
44 else
45 {
46 node = &ossia::net::create_node(root, fmt::format("/out/{}", name));
47 }
48 }
49
50 using val_t = std::decay_t<decltype(f.value)>;
51 return node->create_parameter(oscr::type_for_arg<val_t>());
52 }
53
54 void set_field_value(auto& f, const ossia::value& v)
55 {
56 oscr::from_ossia_value(f, v, f.value);
57 if_possible(f.update(impl));
58 process_on_input();
59 }
60
61 void set_device(ossia::net::device_base& dev) override
62 {
63 // Create the parameters on the device
64 auto& root = dev.get_root_node();
65 inputs.resize(avnd::input_introspection<Node>::size);
66 avnd::input_introspection<Node>::for_all_n(
67 avnd::get_inputs(impl), [&]<std::size_t I>(auto& f, avnd::field_index<I>) {
68 inputs[I] = create_node<true>(root, f);
69 inputs[I]->add_callback(
70 [&f, this](const ossia::value& v) { set_field_value(f, v); });
71 });
72
73 outputs.resize(avnd::output_introspection<Node>::size);
74 avnd::output_introspection<Node>::for_all_n(
75 avnd::get_outputs(impl), [&]<std::size_t I>(auto& f, avnd::field_index<I>) {
76 outputs[I] = create_node<false>(root, f);
77 });
78 }
79
80 bool push(const ossia::net::parameter_base& param, const ossia::value& v) override
81 {
82 // Push on input : process
83 for(int i = 0; i < std::ssize(inputs); i++)
84 {
85 auto* p = inputs[i];
86 if(p == &param)
87 {
88 avnd::input_introspection<Node>::for_nth(
89 avnd::get_inputs(impl), i,
90 [this, &v](auto& f) { this->set_field_value(f, v); });
91 break;
92 }
93 }
94 return false;
95 }
96
97 void process_on_input()
98 {
99 impl();
100
101 avnd::output_introspection<Node>::for_all_n(
102 avnd::get_outputs(impl), [&]<std::size_t I>(auto& f, avnd::field_index<I>) {
103 SCORE_ASSERT(outputs[I]);
104 outputs[I]->set_value(oscr::to_ossia_value(f, f.value));
105 });
106 }
107
108 bool pull(ossia::net::parameter_base&) override { return false; }
109 bool push_raw(const ossia::net::full_parameter_data&) override { return false; }
110 bool observe(ossia::net::parameter_base&, bool) override { return false; }
111 bool update(ossia::net::node_base& node_base) override { return false; }
112
113 Node impl;
114 std::vector<ossia::net::parameter_base*> inputs;
115 std::vector<ossia::net::parameter_base*> outputs;
116};
117
118template <typename Node_T>
120{
121public:
123 const Device::DeviceSettings& settings,
124 const Explorer::DeviceDocumentPlugin& plugin, const score::DocumentContext& ctx)
125 : OwningDeviceInterface{settings}
126 , m_ctx{plugin}
127 {
128 m_capas.canRefreshTree = true;
129 m_capas.canAddNode = false;
130 m_capas.canRemoveNode = false;
131 m_capas.canRenameNode = false;
132 m_capas.canSetProperties = false;
133 m_capas.canSerialize = false;
134 }
135
137
138 bool reconnect() override
139 {
140 disconnect();
141
142 auto protocol = std::make_unique<Protocol<Node_T>>(this->m_ctx.networkContext());
143 auto dev = std::make_unique<ossia::net::generic_device>(
144 std::move(protocol), settings().name.toStdString());
145
146 m_dev = std::move(dev);
147 deviceChanged(nullptr, m_dev.get());
148
149 return connected();
150 }
151 void disconnect() override { OwningDeviceInterface::disconnect(); }
152
153private:
154 const Explorer::DeviceDocumentPlugin& m_ctx;
155};
156
157template <typename Node>
159{
160public:
161 explicit ProtocolSettingsWidget(QWidget* parent = nullptr)
163 {
164 m_deviceNameEdit = new State::AddressFragmentLineEdit{this};
165 m_deviceNameEdit->setText("SpatGRIS");
166 auto layout = new QFormLayout;
167 layout->addRow(tr("Name"), m_deviceNameEdit);
168 setLayout(layout);
169 }
170
171 virtual ~ProtocolSettingsWidget() { }
172
173 Device::DeviceSettings getSettings() const override
174 {
175 // TODO should be = m_settings to follow the other patterns.
177 s.name = m_deviceNameEdit->text();
178 s.protocol = oscr::uuid_from_string<Node>();
179 return s;
180 }
181
182 void setSettings(const Device::DeviceSettings& settings) override
183 {
184 m_deviceNameEdit->setText(settings.name);
185 }
186
187private:
188 QLineEdit* m_deviceNameEdit{};
189};
190
191template <typename Node>
193{
194 UuidKey<Device::ProtocolFactory> concreteKey() const noexcept override
195 {
196 return oscr::uuid_from_string<Node>();
197 }
198
199 QString prettyName() const noexcept override
200 {
201 return QString::fromUtf8(avnd::get_name<Node>().data());
202 }
203 QString category() const noexcept override { return StandardCategories::software; }
204 Device::DeviceEnumerators
205 getEnumerators(const score::DocumentContext& ctx) const override
206 {
207 return {};
208 }
209
210 Device::DeviceInterface* makeDevice(
211 const Device::DeviceSettings& settings,
212 const Explorer::DeviceDocumentPlugin& plugin,
213 const score::DocumentContext& ctx) override
214 {
215 return new DeviceImplementation<Node>{settings, plugin, ctx};
216 }
217
218 const Device::DeviceSettings& defaultSettings() const noexcept override
219 {
220 static const Device::DeviceSettings& settings = [&] {
222 s.protocol = concreteKey();
223 s.name = "SpatGRIS";
224 s.deviceSpecificSettings = QVariant{};
225 return s;
226 }();
227
228 return settings;
229 }
230
231 Device::ProtocolSettingsWidget* makeSettingsWidget() override
232 {
234 }
235
236 QVariant makeProtocolSpecificSettings(const VisitorVariant& visitor) const override
237 {
238 return QVariant{};
239 }
240
241 void serializeProtocolSpecificSettings(
242 const QVariant& data, const VisitorVariant& visitor) const override
243 {
244 }
245
246 bool checkCompatibility(
247 const Device::DeviceSettings& a,
248 const Device::DeviceSettings& b) const noexcept override
249 {
250 return true;
251 }
252};
253
254template <typename... Nodes>
255static void instantiate_device(
256 std::vector<score::InterfaceBase*>& v, const score::ApplicationContext& ctx,
257 const score::InterfaceKey& key)
258{
259 if(key == Device::ProtocolFactory::static_interfaceKey())
260 {
261 (v.emplace_back(
263 ...);
264 }
265}
266}
Definition DeviceInterface.hpp:66
Definition DeviceInterface.hpp:185
Definition ProtocolFactoryInterface.hpp:49
Definition ProtocolSettingsWidget.hpp:22
Definition DefaultProtocolFactory.hpp:10
Definition AddressFragmentLineEdit.hpp:9
Definition UuidKey.hpp:343
Definition AvndDevice.hpp:120
Definition AvndDevice.hpp:193
Definition AvndDevice.hpp:19
Definition AvndDevice.hpp:159
Definition Factories.hpp:19
Definition DeviceSettings.hpp:20
The VisitorVariant struct.
Definition VisitorInterface.hpp:26
Used to access all the application-wide state and structures.
Definition ApplicationContext.hpp:24
Definition DocumentContext.hpp:18