mc_rtc  2.16.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 
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  { return {name, required}; } \
283  \
284  template<typename T = DATAT> \
285  inline auto FNAME(const std::string & name, bool required, T value) \
286  { \
287  if constexpr(std::is_invocable_v<T>) { return details::FormDataInput<T, ELEMENT>{name, required, value}; } \
288  else \
289  { \
290  if constexpr(std::is_same_v<std::decay_t<T>, DATAT>) \
291  { \
292  return details::FormDataInput<DATAT, ELEMENT>{name, required, value}; \
293  } \
294  else \
295  { \
296  return details::FormDataInput<DATAT, ELEMENT>{name, required, DATAT{value}}; \
297  } \
298  } \
299  }
300 
301 #define MAKE_INTERACTIVE_DATA_INPUT_HELPER(DATAT, ELEMENT, FNAME) \
302  inline details::FormInteractiveDataInput<DATAT, ELEMENT> FNAME(const std::string & name, bool required, \
303  bool interactive = true) \
304  { return {name, required, interactive}; } \
305  \
306  template<typename T = DATAT, typename = std::enable_if_t<!std::is_same_v<T, bool>>> \
307  inline auto FNAME(const std::string & name, bool required, T value, bool interactive = true) \
308  { \
309  if constexpr(std::is_invocable_v<T>) \
310  { \
311  return details::FormInteractiveDataInput<T, ELEMENT>{name, required, value, interactive}; \
312  } \
313  else \
314  { \
315  if constexpr(std::is_same_v<std::decay_t<T>, DATAT>) \
316  { \
317  return details::FormInteractiveDataInput<DATAT, ELEMENT>{name, required, value, interactive}; \
318  } \
319  else \
320  { \
321  return details::FormInteractiveDataInput<DATAT, ELEMENT>{name, required, DATAT{value}, interactive}; \
322  } \
323  } \
324  }
325 
326 MAKE_DATA_INPUT_HELPER(bool, Elements::Checkbox, FormCheckbox)
327 MAKE_DATA_INPUT_HELPER(int, Elements::IntegerInput, FormIntegerInput)
328 MAKE_DATA_INPUT_HELPER(double, Elements::NumberInput, FormNumberInput)
329 MAKE_DATA_INPUT_HELPER(std::string, Elements::StringInput, FormStringInput)
330 MAKE_INTERACTIVE_DATA_INPUT_HELPER(Eigen::Vector3d, Elements::Point3D, FormPoint3DInput)
333 
334 #undef MAKE_DATA_INPUT_HELPER
335 #undef MAKE_INTERACTIVE_DATA_INPUT_HELPER
336 
337 namespace details
338 {
339 
340 template<typename T>
341 struct FormArrayInput : public FormElement<FormArrayInput<T>, Elements::ArrayInput>
342 {
343  FormArrayInput(const std::string & name,
344  bool required,
345  const std::vector<std::string> & labels,
346  const T & def,
347  bool fixed_size = true)
348  : FormElement<FormArrayInput<T>, Elements::ArrayInput>(name, required), def_{def}, fixed_size_(fixed_size),
349  has_def_(true), labels_(labels)
350  {
351  }
352 
353  FormArrayInput(const std::string & name,
354  bool required,
355  const std::vector<std::string> & labels = {},
356  bool fixed_size = false)
357  : FormArrayInput<T>(name, required, labels, {}, fixed_size)
358  { has_def_ = false; }
359 
360  static constexpr size_t write_size_() { return 4; }
361 
362  static constexpr bool is_dynamic() { return CallbackOrValue<T>::is_callback; }
363 
365  {
366  def_.write(builder);
367  builder.write(fixed_size_);
368  builder.write(has_def_);
369  builder.write(labels_);
370  }
371 
372 private:
373  CallbackOrValue<T> def_;
374  bool fixed_size_;
375  bool has_def_;
376  std::vector<std::string> labels_;
377 };
378 
379 } // namespace details
380 
381 template<typename T>
382 details::FormArrayInput<T> FormArrayInput(const std::string & name, bool required, bool fixed_size = false)
383 {
384  using Labels = details::Labels<T>;
385  return {name, required, Labels::labels, fixed_size};
386 }
387 
388 template<typename T>
389 auto FormArrayInput(const std::string & name, bool required, T && value, bool fixed_size = true)
390 {
391  if constexpr(std::is_invocable_v<T>)
392  {
393  using DataT = std::decay_t<decltype(std::declval<T>()())>;
394  using Labels = details::Labels<DataT>;
395  return details::FormArrayInput{name, required, Labels::labels, std::forward<T>(value), fixed_size};
396  }
397  else
398  {
399  using DataT = std::decay_t<T>;
400  using Labels = details::Labels<DataT>;
401  return details::FormArrayInput<DataT>{name, required, Labels::labels, std::forward<T>(value), fixed_size};
402  }
403 }
404 
405 struct FormComboInput : public FormElement<FormComboInput, Elements::ComboInput>
406 {
407  inline FormComboInput(const std::string & name,
408  bool required,
409  const std::vector<std::string> & values,
410  bool send_index = false,
411  int def = -1)
412  : FormElement<FormComboInput, Elements::ComboInput>(name, required), values_(values), send_index_(send_index),
413  def_(def)
414  {
415  }
416 
417  static constexpr size_t write_size_() { return 3; }
418 
419  inline void write_(mc_rtc::MessagePackBuilder & builder)
420  {
421  builder.write(values_);
422  builder.write(send_index_);
423  builder.write(def_);
424  }
425 
427  inline FormComboInput() {}
428 
429 private:
430  std::vector<std::string> values_;
431  bool send_index_ = false;
432  int def_;
433 };
434 
435 struct FormDataComboInput : public FormElement<FormDataComboInput, Elements::DataComboInput>
436 {
437  inline FormDataComboInput(const std::string & name,
438  bool required,
439  const std::vector<std::string> & ref,
440  bool send_index = false)
441  : FormElement<FormDataComboInput, Elements::DataComboInput>(name, required), ref_(ref), send_index_(send_index)
442  {
443  }
444 
445  static constexpr size_t write_size_() { return 2; }
446 
447  inline void write_(mc_rtc::MessagePackBuilder & builder)
448  {
449  builder.write(ref_);
450  builder.write(send_index_);
451  }
452 
454  inline FormDataComboInput() {}
455 
456 private:
457  std::vector<std::string> ref_;
458  bool send_index_;
459 };
460 
466 struct FormObjectInput : public FormElement<FormObjectInput, Elements::Form>, details::FormElements
467 {
468  template<typename... Args>
469  FormObjectInput(const std::string & name, bool required, Args &&... args)
470  : FormElement<FormObjectInput, Elements::Form>(name, required), FormElements(std::forward<Args>(args)...)
471  {
472  }
473 
474  static constexpr bool is_dynamic() { return true; }
475 
476  static constexpr size_t write_size_() { return 1; }
477 
478  void write_(mc_rtc::MessagePackBuilder & builder) { FormElements::write_impl(builder); }
479 };
480 
492 template<typename T = details::VoidValue>
493 struct FormGenericArrayInput : public FormElement<FormGenericArrayInput<T>, Elements::GenericArray>,
495 {
496  template<typename = std::enable_if_t<!details::is_form_element_v<T>>>
497  FormGenericArrayInput(const std::string & name, bool required, T data = {})
499  {
500  }
501 
502  template<typename Element, typename = std::enable_if_t<details::is_form_element_v<Element>>>
503  FormGenericArrayInput(const std::string & name, bool required, Element && element, T data = {})
505  FormElements(std::forward<Element>(element)), data_{data}
506  {
507  }
508 
509  static constexpr bool is_dynamic() { return true; }
510 
511  static constexpr size_t write_size_() { return 2; }
512 
514  {
515  if(count_ != 1) { mc_rtc::log::error_and_throw("FormGenericArrayInput must have exactly one element"); }
516  FormElements::write_impl(builder);
517  data_.write(builder);
518  }
519 
520 private:
522 };
523 
534 template<typename T = details::VoidValue>
535 struct FormOneOfInput : public FormElement<FormOneOfInput<T>, Elements::OneOf>, details::FormElements
536 {
537  FormOneOfInput(const std::string & name, bool required)
538  : FormElement<FormOneOfInput, Elements::OneOf>(name, required), FormElements()
539  {
540  }
541 
542  template<typename U,
543  typename... Args,
544  typename = std::enable_if_t<!details::is_variant_v<std::decay_t<U>> && !details::is_getter<U>()>>
545  FormOneOfInput(const std::string & name, bool required, U && arg, Args &&... args)
546  : FormElement<FormOneOfInput, Elements::OneOf>(name, required),
547  FormElements(std::forward<U>(arg), std::forward<Args>(args)...)
548  {
549  }
550 
551  template<typename... Args>
552  FormOneOfInput(const std::string & name, bool required, const T & def, Args &&... args)
553  : FormElement<FormOneOfInput, Elements::OneOf>(name, required), FormElements(std::forward<Args>(args)...), def_(def)
554  {
555  }
556 
557  static constexpr bool is_dynamic() { return true; }
558 
559  static constexpr size_t write_size_() { return 2; }
560 
562  {
563  def_.write(builder);
564  FormElements::write_impl(builder);
565  }
566 
567 private:
569 };
570 
572 template<typename Callback, typename... Args>
573 auto Form(const std::string & name, Callback cb, Args &&... args)
574 { return details::FormImpl(name, cb, std::forward<Args>(args)...); }
575 
576 } // 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:301
std::optional< Eigen::VectorXd > value
constexpr bool is_form_element_v
Definition: Form.h:137
auto write(T &value)
Definition: traits.h:226
Definition: Observer.h:16
auto Form(const std::string &name, Callback cb, Args &&... args)
Definition: Form.h:573
details::FormArrayInput< T > FormArrayInput(const std::string &name, bool required, bool fixed_size=false)
Definition: Form.h:382
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(const S &format, Args &&... args)
Definition: logging.h:40
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:406
FormComboInput()
Definition: Form.h:427
FormComboInput(const std::string &name, bool required, const std::vector< std::string > &values, bool send_index=false, int def=-1)
Definition: Form.h:407
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:419
static constexpr size_t write_size_()
Definition: Form.h:417
Definition: Form.h:436
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:447
static constexpr size_t write_size_()
Definition: Form.h:445
FormDataComboInput(const std::string &name, bool required, const std::vector< std::string > &ref, bool send_index=false)
Definition: Form.h:437
FormDataComboInput()
Definition: Form.h:454
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:513
static constexpr bool is_dynamic()
Definition: Form.h:509
FormGenericArrayInput(const std::string &name, bool required, Element &&element, T data={})
Definition: Form.h:503
static constexpr size_t write_size_()
Definition: Form.h:511
FormGenericArrayInput(const std::string &name, bool required, T data={})
Definition: Form.h:497
Definition: Form.h:467
FormObjectInput(const std::string &name, bool required, Args &&... args)
Definition: Form.h:469
static constexpr bool is_dynamic()
Definition: Form.h:474
static constexpr size_t write_size_()
Definition: Form.h:476
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:478
Definition: Form.h:536
FormOneOfInput(const std::string &name, bool required, const T &def, Args &&... args)
Definition: Form.h:552
static constexpr size_t write_size_()
Definition: Form.h:559
FormOneOfInput(const std::string &name, bool required)
Definition: Form.h:537
void write_(mc_rtc::MessagePackBuilder &builder)
Definition: Form.h:561
static constexpr bool is_dynamic()
Definition: Form.h:557
FormOneOfInput(const std::string &name, bool required, U &&arg, Args &&... args)
Definition: Form.h:545
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:364
static constexpr bool is_dynamic()
Definition: Form.h:362
static constexpr size_t write_size_()
Definition: Form.h:360
FormArrayInput(const std::string &name, bool required, const std::vector< std::string > &labels={}, bool fixed_size=false)
Definition: Form.h:353
FormArrayInput(const std::string &name, bool required, const std::vector< std::string > &labels, const T &def, bool fixed_size=true)
Definition: Form.h:343
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:116
Definition: Form.h:196
static std::false_type test(...)
static auto test(T *) -> typename T::is_form_element_t