mc_rtc  2.14.0
Form.h
Go to the documentation of this file.
1 /*
2  * Copyright 2015-2019 CNRS-UM LIRMM, CNRS-AIST JRL
3  */
4 
5 #pragma once
6 
8 #include <mc_rtc/gui/elements.h>
9 
10 #include <mc_rtc/logging.h>
11 
12 namespace mc_rtc::gui
13 {
14 
15 namespace details
16 {
17 
20 {
21  template<typename... Args>
22  FormElements(Args &&... args)
23  {
25  count_ = sizeof...(Args);
26  write_elements(builder, std::forward<Args>(args)...);
27  data_size_ = builder.finish();
28  }
29 
30  template<typename T>
31  void addElement(T && element)
32  {
33  count_ += 1;
34  using ElementT = typename std::decay<T>::type;
35  if(ElementT::is_dynamic()) { addDynamicElement(std::forward<T>(element)); }
36  else
37  {
38  std::vector<char> data = data_;
40  builder.write_object(data.data(), data_size_);
41  builder.start_array(element.write_size());
42  element.write(builder);
43  builder.finish_array();
44  data_size_ = builder.finish();
45  }
46  }
47 
49  {
50  builder.start_array(count_);
51  for(const auto & el : dynamic_elements_) { el(builder); }
52  builder.write_object(data_.data(), data_size_);
53  for(size_t i = dynamic_elements_.size() + 1; i < count_; ++i) { builder.write_object(nullptr, 0); }
54  builder.finish_array();
55  }
56 
57 protected:
58  template<typename... Args>
60  {
61  }
62 
63  template<typename Arg, typename... Args>
64  void write_elements(mc_rtc::MessagePackBuilder & builder, Arg && element, Args &&... args)
65  {
66  using ElementT = typename std::decay<Arg>::type;
67  if(ElementT::is_dynamic()) { addDynamicElement(std::forward<Arg>(element)); }
68  else
69  {
70  builder.start_array(element.write_size());
71  element.write(builder);
72  builder.finish_array();
73  }
74  write_elements(builder, std::forward<Args>(args)...);
75  }
76 
77  template<typename T>
78  void addDynamicElement(T && element)
79  {
80  auto callback = [element](mc_rtc::MessagePackBuilder & builder) mutable
81  {
82  builder.start_array(element.write_size());
83  element.write(builder);
84  builder.finish_array();
85  };
86  dynamic_elements_.push_back(callback);
87  }
88 
89  size_t count_;
90  std::vector<std::function<void(mc_rtc::MessagePackBuilder &)>> dynamic_elements_;
91  std::vector<char> data_;
92  size_t data_size_;
93 };
94 
103 template<typename Callback>
104 struct FormImpl : public CallbackElement<Element, Callback>, FormElements
105 {
106  static constexpr auto type = Elements::Form;
107 
108  template<typename... Args>
109  FormImpl(const std::string & name, Callback cb, Args &&... args)
110  : CallbackElement<Element, Callback>(name, cb), FormElements(std::forward<Args>(args)...)
111  {
112  }
113 
114  static constexpr size_t write_size() { return CallbackElement<Element, Callback>::write_size() + 1; }
115 
117  {
119  FormElements::write_impl(builder);
120  }
121 
123  FormImpl() {}
124 };
125 
128 {
129  template<typename T>
130  static auto test(T *) -> typename T::is_form_element_t;
131 
132  template<typename T>
133  static std::false_type test(...);
134 };
135 
136 template<typename T>
137 inline constexpr bool is_form_element_v = decltype(is_form_element::test<T>(nullptr))::value;
138 
139 } // namespace details
140 
141 template<typename Derived, Elements element>
143 {
144  using is_form_element_t = std::true_type;
145 
146  static constexpr auto type = element;
147 
148  static constexpr size_t write_size() { return 3 + Derived::write_size_(); }
149 
150  static constexpr bool is_dynamic() { return false; }
151 
153  {
154  builder.write(name_);
155  builder.write(static_cast<typename std::underlying_type<Elements>::type>(type));
156  builder.write(required_);
157  static_cast<Derived &>(*this).write_(builder);
158  }
159 
162 
163 protected:
164  FormElement(const std::string & name, bool required) : name_(name), required_(required) {}
165 
166  std::string name_;
167  bool required_;
168 };
169 
170 namespace details
171 {
172 
174 template<typename T>
176 {
177  static_assert(std::is_same_v<std::decay_t<T>, T>);
178 
179  CallbackOrValue(T value) : callback_or_value(value) {}
180 
182 
183  static inline constexpr bool is_callback = std::is_invocable_v<T>;
184 
186  {
187  if constexpr(is_callback) { builder.write(callback_or_value()); }
188  else
189  {
190  builder.write(callback_or_value);
191  }
192  }
193 };
194 
195 struct VoidValue
196 {
197 };
198 
199 template<>
201 {
204 
205  static inline constexpr bool is_callback = false;
206 
207  void write(mc_rtc::MessagePackBuilder & builder) { builder.write(); }
208 };
209 
210 template<typename T>
212 {
213  FormDataInputBase(const T & def) : def_{def}, has_def_(true) {}
214 
215  FormDataInputBase() : FormDataInputBase(T{}) { has_def_ = false; }
216 
217  static constexpr size_t write_size_() { return 2; }
218 
219  static constexpr bool is_dynamic_() { return CallbackOrValue<T>::is_callback; }
220 
222  {
223  def_.write(builder);
224  builder.write(has_def_);
225  }
226 
227 private:
228  CallbackOrValue<T> def_;
229  bool has_def_;
230 };
231 
232 template<typename T, Elements element>
233 struct FormDataInput : public FormElement<FormDataInput<T, element>, element>, FormDataInputBase<T>
234 {
235  FormDataInput(const std::string & name, bool required, const T & def)
236  : FormElement<FormDataInput<T, element>, element>(name, required), FormDataInputBase<T>(def)
237  {
238  }
239 
240  FormDataInput(const std::string & name, bool required)
241  : FormElement<FormDataInput<T, element>, element>(name, required), FormDataInputBase<T>()
242  {
243  }
244 
245  static constexpr bool is_dynamic() { return FormDataInputBase<T>::is_dynamic_(); }
246 };
247 
248 template<typename T, Elements element>
249 struct FormInteractiveDataInput : public FormElement<FormInteractiveDataInput<T, element>, element>,
251 {
252  FormInteractiveDataInput(const std::string & name, bool required, const T & def, bool interactive = true)
253  : FormElement<FormInteractiveDataInput<T, element>, element>(name, required), FormDataInputBase<T>(def),
254  interactive_(interactive)
255  {
256  }
257 
258  FormInteractiveDataInput(const std::string & name, bool required, bool interactive)
259  : FormElement<FormInteractiveDataInput<T, element>, element>(name, required), FormDataInputBase<T>(),
260  interactive_(interactive)
261  {
262  }
263 
264  static constexpr bool is_dynamic() { return FormDataInputBase<T>::is_dynamic_(); }
265 
266  static constexpr size_t write_size_() { return FormDataInputBase<T>::write_size_() + 1; }
267 
269  {
271  builder.write(interactive_);
272  }
273 
274 private:
275  bool interactive_;
276 };
277 
278 } // namespace details
279 
280 #define MAKE_DATA_INPUT_HELPER(DATAT, ELEMENT, FNAME) \
281  inline details::FormDataInput<DATAT, ELEMENT> FNAME(const std::string & name, bool required) \
282  { \
283  return {name, required}; \
284  } \
285  \
286  template<typename T = DATAT> \
287  inline auto FNAME(const std::string & name, bool required, T value) \
288  { \
289  if constexpr(std::is_invocable_v<T>) { return details::FormDataInput<T, ELEMENT>{name, required, value}; } \
290  else \
291  { \
292  if constexpr(std::is_same_v<std::decay_t<T>, DATAT>) \
293  { \
294  return details::FormDataInput<DATAT, ELEMENT>{name, required, value}; \
295  } \
296  else \
297  { \
298  return details::FormDataInput<DATAT, ELEMENT>{name, required, DATAT{value}}; \
299  } \
300  } \
301  }
302 
303 #define MAKE_INTERACTIVE_DATA_INPUT_HELPER(DATAT, ELEMENT, FNAME) \
304  inline details::FormInteractiveDataInput<DATAT, ELEMENT> FNAME(const std::string & name, bool required, \
305  bool interactive = true) \
306  { \
307  return {name, required, interactive}; \
308  } \
309  \
310  template<typename T = DATAT, typename = std::enable_if_t<!std::is_same_v<T, bool>>> \
311  inline auto FNAME(const std::string & name, bool required, T value, bool interactive = true) \
312  { \
313  if constexpr(std::is_invocable_v<T>) \
314  { \
315  return details::FormInteractiveDataInput<T, ELEMENT>{name, required, value, interactive}; \
316  } \
317  else \
318  { \
319  if constexpr(std::is_same_v<std::decay_t<T>, DATAT>) \
320  { \
321  return details::FormInteractiveDataInput<DATAT, ELEMENT>{name, required, value, interactive}; \
322  } \
323  else \
324  { \
325  return details::FormInteractiveDataInput<DATAT, ELEMENT>{name, required, DATAT{value}, interactive}; \
326  } \
327  } \
328  }
329 
330 MAKE_DATA_INPUT_HELPER(bool, Elements::Checkbox, FormCheckbox)
331 MAKE_DATA_INPUT_HELPER(int, Elements::IntegerInput, FormIntegerInput)
332 MAKE_DATA_INPUT_HELPER(double, Elements::NumberInput, FormNumberInput)
333 MAKE_DATA_INPUT_HELPER(std::string, Elements::StringInput, FormStringInput)
334 MAKE_INTERACTIVE_DATA_INPUT_HELPER(Eigen::Vector3d, Elements::Point3D, FormPoint3DInput)
335 MAKE_INTERACTIVE_DATA_INPUT_HELPER(sva::PTransformd, Elements::Rotation, FormRotationInput)
336 MAKE_INTERACTIVE_DATA_INPUT_HELPER(sva::PTransformd, Elements::Transform, FormTransformInput)
337 
338 #undef MAKE_DATA_INPUT_HELPER
339 #undef MAKE_INTERACTIVE_DATA_INPUT_HELPER
340 
341 namespace details
342 {
343 
344 template<typename T>
345 struct FormArrayInput : public FormElement<FormArrayInput<T>, Elements::ArrayInput>
346 {
347  FormArrayInput(const std::string & name,
348  bool required,
349  const std::vector<std::string> & labels,
350  const T & def,
351  bool fixed_size = true)
352  : FormElement<FormArrayInput<T>, Elements::ArrayInput>(name, required), def_{def}, fixed_size_(fixed_size),
353  has_def_(true), labels_(labels)
354  {
355  }
356 
357  FormArrayInput(const std::string & name,
358  bool required,
359  const std::vector<std::string> & labels = {},
360  bool fixed_size = false)
361  : FormArrayInput<T>(name, required, labels, {}, fixed_size)
362  {
363  has_def_ = false;
364  }
365 
366  static constexpr size_t write_size_() { return 4; }
367 
368  static constexpr bool is_dynamic() { return CallbackOrValue<T>::is_callback; }
369 
371  {
372  def_.write(builder);
373  builder.write(fixed_size_);
374  builder.write(has_def_);
375  builder.write(labels_);
376  }
377 
378 private:
379  CallbackOrValue<T> def_;
380  bool fixed_size_;
381  bool has_def_;
382  std::vector<std::string> labels_;
383 };
384 
385 } // namespace details
386 
387 template<typename T>
388 details::FormArrayInput<T> FormArrayInput(const std::string & name, bool required, bool fixed_size = false)
389 {
390  using Labels = details::Labels<T>;
391  return {name, required, Labels::labels, fixed_size};
392 }
393 
394 template<typename T>
395 auto FormArrayInput(const std::string & name, bool required, T && value, bool fixed_size = true)
396 {
397  if constexpr(std::is_invocable_v<T>)
398  {
399  using DataT = std::decay_t<decltype(std::declval<T>()())>;
400  using Labels = details::Labels<DataT>;
401  return details::FormArrayInput{name, required, Labels::labels, std::forward<T>(value), fixed_size};
402  }
403  else
404  {
405  using DataT = std::decay_t<T>;
406  using Labels = details::Labels<DataT>;
407  return details::FormArrayInput<DataT>{name, required, Labels::labels, std::forward<T>(value), fixed_size};
408  }
409 }
410 
411 struct FormComboInput : public FormElement<FormComboInput, Elements::ComboInput>
412 {
413  inline FormComboInput(const std::string & name,
414  bool required,
415  const std::vector<std::string> & values,
416  bool send_index = false,
417  int def = -1)
418  : FormElement<FormComboInput, Elements::ComboInput>(name, required), values_(values), send_index_(send_index),
419  def_(def)
420  {
421  }
422 
423  static constexpr size_t write_size_() { return 3; }
424 
425  inline void write_(mc_rtc::MessagePackBuilder & builder)
426  {
427  builder.write(values_);
428  builder.write(send_index_);
429  builder.write(def_);
430  }
431 
433  inline FormComboInput() {}
434 
435 private:
436  std::vector<std::string> values_;
437  bool send_index_ = false;
438  int def_;
439 };
440 
441 struct FormDataComboInput : public FormElement<FormDataComboInput, Elements::DataComboInput>
442 {
443  inline FormDataComboInput(const std::string & name,
444  bool required,
445  const std::vector<std::string> & ref,
446  bool send_index = false)
447  : FormElement<FormDataComboInput, Elements::DataComboInput>(name, required), ref_(ref), send_index_(send_index)
448  {
449  }
450 
451  static constexpr size_t write_size_() { return 2; }
452 
453  inline void write_(mc_rtc::MessagePackBuilder & builder)
454  {
455  builder.write(ref_);
456  builder.write(send_index_);
457  }
458 
460  inline FormDataComboInput() {}
461 
462 private:
463  std::vector<std::string> ref_;
464  bool send_index_;
465 };
466 
472 struct FormObjectInput : public FormElement<FormObjectInput, Elements::Form>, details::FormElements
473 {
474  template<typename... Args>
475  FormObjectInput(const std::string & name, bool required, Args &&... args)
476  : FormElement<FormObjectInput, Elements::Form>(name, required), FormElements(std::forward<Args>(args)...)
477  {
478  }
479 
480  static constexpr bool is_dynamic() { return true; }
481 
482  static constexpr size_t write_size_() { return 1; }
483 
484  void write_(mc_rtc::MessagePackBuilder & builder) { FormElements::write_impl(builder); }
485 };
486 
498 template<typename T = details::VoidValue>
499 struct FormGenericArrayInput : public FormElement<FormGenericArrayInput<T>, Elements::GenericArray>,
501 {
502  template<typename = std::enable_if_t<!details::is_form_element_v<T>>>
503  FormGenericArrayInput(const std::string & name, bool required, T data = {})
505  {
506  }
507 
508  template<typename Element, typename = std::enable_if_t<details::is_form_element_v<Element>>>
509  FormGenericArrayInput(const std::string & name, bool required, Element && element, T data = {})
511  FormElements(std::forward<Element>(element)), data_{data}
512  {
513  }
514 
515  static constexpr bool is_dynamic() { return true; }
516 
517  static constexpr size_t write_size_() { return 2; }
518 
520  {
521  if(count_ != 1) { mc_rtc::log::error_and_throw("FormGenericArrayInput must have exactly one element"); }
522  FormElements::write_impl(builder);
523  data_.write(builder);
524  }
525 
526 private:
528 };
529 
540 template<typename T = details::VoidValue>
541 struct FormOneOfInput : public FormElement<FormOneOfInput<T>, Elements::OneOf>, details::FormElements
542 {
543  FormOneOfInput(const std::string & name, bool required)
544  : FormElement<FormOneOfInput, Elements::OneOf>(name, required), FormElements()
545  {
546  }
547 
548  template<typename U,
549  typename... Args,
550  typename = std::enable_if_t<!details::is_variant_v<std::decay_t<U>> && !details::is_getter<U>()>>
551  FormOneOfInput(const std::string & name, bool required, U && arg, Args &&... args)
552  : FormElement<FormOneOfInput, Elements::OneOf>(name, required),
553  FormElements(std::forward<U>(arg), std::forward<Args>(args)...)
554  {
555  }
556 
557  template<typename... Args>
558  FormOneOfInput(const std::string & name, bool required, const T & def, Args &&... args)
559  : FormElement<FormOneOfInput, Elements::OneOf>(name, required), FormElements(std::forward<Args>(args)...), def_(def)
560  {
561  }
562 
563  static constexpr bool is_dynamic() { return true; }
564 
565  static constexpr size_t write_size_() { return 2; }
566 
568  {
569  def_.write(builder);
570  FormElements::write_impl(builder);
571  }
572 
573 private:
575 };
576 
578 template<typename Callback, typename... Args>
579 auto Form(const std::string & name, Callback cb, Args &&... args)
580 {
581  return details::FormImpl(name, cb, std::forward<Args>(args)...);
582 }
583 
584 } // namespace mc_rtc::gui
#define MAKE_DATA_INPUT_HELPER(DATAT, ELEMENT, FNAME)
Definition: Form.h:280
#define MAKE_INTERACTIVE_DATA_INPUT_HELPER(DATAT, ELEMENT, FNAME)
Definition: Form.h:303
constexpr bool is_form_element_v
Definition: Form.h:137
auto write(T &value)
Definition: traits.h:230
Definition: Observer.h:16
auto Form(const std::string &name, Callback cb, Args &&... args)
Definition: Form.h:579
details::FormArrayInput< T > FormArrayInput(const std::string &name, bool required, bool fixed_size=false)
Definition: Form.h:388
Elements
Definition: elements.h:23
auto ArrayInput(const std::string &name, GetT get_fn, SetT set_fn)
Definition: ArrayInput.h:59
auto ComboInput(const std::string &name, const std::vector< std::string > &values, GetT get_fn, SetT set_fn)
Definition: ComboInput.h:52
auto DataComboInput(const std::string &name, const std::vector< std::string > &values, GetT get_fn, SetT set_fn)
Definition: DataComboInput.h:51
void error_and_throw(Args &&... args)
Definition: logging.h:47
Definition: Contact.h:67
Definition: MessagePackBuilder.h:87
void start_array(size_t size)
void write_object(const char *data, size_t s)
Definition: elements.h:127
Definition: elements.h:59
const std::string & name() const
Definition: elements.h:61
Definition: Form.h:412
FormComboInput()
Definition: Form.h:433
FormComboInput(const std::string &name, bool required, const std::vector< std::string > &values, bool send_index=false, int def=-1)
Definition: Form.h:413
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:425
static constexpr size_t write_size_()
Definition: Form.h:423
Definition: Form.h:442
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:453
static constexpr size_t write_size_()
Definition: Form.h:451
FormDataComboInput(const std::string &name, bool required, const std::vector< std::string > &ref, bool send_index=false)
Definition: Form.h:443
FormDataComboInput()
Definition: Form.h:460
Definition: Form.h:143
static constexpr size_t write_size()
Definition: Form.h:148
bool required_
Definition: Form.h:167
std::string name_
Definition: Form.h:166
FormElement(const std::string &name, bool required)
Definition: Form.h:164
FormElement()
Definition: Form.h:161
std::true_type is_form_element_t
Definition: Form.h:144
void write(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:152
static constexpr auto type
Definition: Form.h:146
static constexpr bool is_dynamic()
Definition: Form.h:150
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:519
static constexpr bool is_dynamic()
Definition: Form.h:515
FormGenericArrayInput(const std::string &name, bool required, Element &&element, T data={})
Definition: Form.h:509
static constexpr size_t write_size_()
Definition: Form.h:517
FormGenericArrayInput(const std::string &name, bool required, T data={})
Definition: Form.h:503
Definition: Form.h:473
FormObjectInput(const std::string &name, bool required, Args &&... args)
Definition: Form.h:475
static constexpr bool is_dynamic()
Definition: Form.h:480
static constexpr size_t write_size_()
Definition: Form.h:482
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:484
Definition: Form.h:542
FormOneOfInput(const std::string &name, bool required, const T &def, Args &&... args)
Definition: Form.h:558
static constexpr size_t write_size_()
Definition: Form.h:565
FormOneOfInput(const std::string &name, bool required)
Definition: Form.h:543
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:567
static constexpr bool is_dynamic()
Definition: Form.h:563
FormOneOfInput(const std::string &name, bool required, U &&arg, Args &&... args)
Definition: Form.h:551
CallbackOrValue(VoidValue)
Definition: Form.h:203
void write(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:207
void write(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:185
CallbackOrValue(T value)
Definition: Form.h:179
T callback_or_value
Definition: Form.h:181
static constexpr bool is_callback
Definition: Form.h:183
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:370
static constexpr bool is_dynamic()
Definition: Form.h:368
static constexpr size_t write_size_()
Definition: Form.h:366
FormArrayInput(const std::string &name, bool required, const std::vector< std::string > &labels={}, bool fixed_size=false)
Definition: Form.h:357
FormArrayInput(const std::string &name, bool required, const std::vector< std::string > &labels, const T &def, bool fixed_size=true)
Definition: Form.h:347
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:221
static constexpr size_t write_size_()
Definition: Form.h:217
static constexpr bool is_dynamic_()
Definition: Form.h:219
FormDataInputBase()
Definition: Form.h:215
FormDataInputBase(const T &def)
Definition: Form.h:213
FormDataInput(const std::string &name, bool required)
Definition: Form.h:240
static constexpr bool is_dynamic()
Definition: Form.h:245
FormDataInput(const std::string &name, bool required, const T &def)
Definition: Form.h:235
void write_impl(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:48
void addElement(T &&element)
Definition: Form.h:31
size_t data_size_
Definition: Form.h:92
FormElements(Args &&... args)
Definition: Form.h:22
void write_elements(mc_rtc::MessagePackBuilder &, Args &&...)
Definition: Form.h:59
size_t count_
Definition: Form.h:89
std::vector< char > data_
Definition: Form.h:91
std::vector< std::function< void(mc_rtc::MessagePackBuilder &)> > dynamic_elements_
Definition: Form.h:90
void write_elements(mc_rtc::MessagePackBuilder &builder, Arg &&element, Args &&... args)
Definition: Form.h:64
void addDynamicElement(T &&element)
Definition: Form.h:78
Definition: Form.h:105
static constexpr auto type
Definition: Form.h:106
FormImpl(const std::string &name, Callback cb, Args &&... args)
Definition: Form.h:109
FormImpl()
Definition: Form.h:123
void write(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:116
static constexpr size_t write_size()
Definition: Form.h:114
FormInteractiveDataInput(const std::string &name, bool required, bool interactive)
Definition: Form.h:258
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:268
static constexpr bool is_dynamic()
Definition: Form.h:264
static constexpr size_t write_size_()
Definition: Form.h:266
FormInteractiveDataInput(const std::string &name, bool required, const T &def, bool interactive=true)
Definition: Form.h:252
Definition: traits.h:120
Definition: Form.h:196
static std::false_type test(...)
static auto test(T *) -> typename T::is_form_element_t