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