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 
15 namespace oscr
16 {
17 template <typename Node>
18 class Protocol final : public ossia::net::protocol_base
19 {
20 public:
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 
118 template <typename Node_T>
120 {
121 public:
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 
136  ~DeviceImplementation() { }
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 
153 private:
154  const Explorer::DeviceDocumentPlugin& m_ctx;
155 };
156 
157 template <typename Node>
159 {
160 public:
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 
187 private:
188  QLineEdit* m_deviceNameEdit{};
189 };
190 
191 template <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  {
233  return new ProtocolSettingsWidget<Node>;
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 
254 template <typename... Nodes>
255 static 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:47
Definition: ProtocolSettingsWidget.hpp:22
Definition: DefaultProtocolFactory.hpp:10
Definition: AddressFragmentLineEdit.hpp:9
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