TGUI  0.8-dev
SignalImpl.hpp
1 //
3 // TGUI - Texus' Graphical User Interface
4 // Copyright (C) 2012-2017 Bruno Van de Velde (vdv_b@tgui.eu)
5 //
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors be held liable for any damages arising from the use of this software.
8 //
9 // Permission is granted to anyone to use this software for any purpose,
10 // including commercial applications, and to alter it and redistribute it freely,
11 // subject to the following restrictions:
12 //
13 // 1. The origin of this software must not be misrepresented;
14 // you must not claim that you wrote the original software.
15 // If you use this software in a product, an acknowledgment
16 // in the product documentation would be appreciated but is not required.
17 //
18 // 2. Altered source versions must be plainly marked as such,
19 // and must not be misrepresented as being the original software.
20 //
21 // 3. This notice may not be removed or altered from any source distribution.
22 //
24 
25 
26 #ifndef TGUI_SIGNAL_IMPL_HPP
27 #define TGUI_SIGNAL_IMPL_HPP
28 
29 #include <TGUI/Signal.hpp>
30 
32 
33 namespace tgui
34 {
35  namespace internal_signal
36  {
37  // make_integer_sequence implementation taken from https://gist.github.com/jappa/62f30b6da5adea60bad3
38  #ifdef TGUI_NO_CPP14
39  template <class Type, Type... Indices>
40  struct integer_sequence
41  {
42  typedef Type value_type;
43  static std::size_t size()
44  {
45  return sizeof...(Indices);
46  }
47  };
48 
49  template<std::size_t... Ints>
50  using index_sequence = integer_sequence<std::size_t, Ints...>;
51 
52  namespace integer_sequence_detail
53  {
54  template <typename T, std::size_t ..._Extra>
55  struct repeat;
56 
57  template <typename T, T ...N, std::size_t ..._Extra>
58  struct repeat<integer_sequence<T, N...>, _Extra...>
59  {
60  typedef integer_sequence<T, N...,
61  1 * sizeof...(N) + N...,
62  2 * sizeof...(N) + N...,
63  3 * sizeof...(N) + N...,
64  4 * sizeof...(N) + N...,
65  5 * sizeof...(N) + N...,
66  6 * sizeof...(N) + N...,
67  7 * sizeof...(N) + N...,
68  _Extra...> type;
69  };
70 
71  template <std::size_t N> struct parity;
72  template <std::size_t N> struct make:parity<N % 8>::template pmake<N> {};
73 
74  template <> struct make<0> { typedef integer_sequence<std::size_t> type; };
75  template <> struct make<1> { typedef integer_sequence<std::size_t, 0> type; };
76  template <> struct make<2> { typedef integer_sequence<std::size_t, 0, 1> type; };
77  template <> struct make<3> { typedef integer_sequence<std::size_t, 0, 1, 2> type; };
78  template <> struct make<4> { typedef integer_sequence<std::size_t, 0, 1, 2, 3> type; };
79  template <> struct make<5> { typedef integer_sequence<std::size_t, 0, 1, 2, 3, 4> type; };
80  template <> struct make<6> { typedef integer_sequence<std::size_t, 0, 1, 2, 3, 4, 5> type; };
81  template <> struct make<7> { typedef integer_sequence<std::size_t, 0, 1, 2, 3, 4, 5, 6> type; };
82 
83  template <> struct parity<0> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type> {}; };
84  template <> struct parity<1> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 1> {}; };
85  template <> struct parity<2> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 2, N - 1> {}; };
86  template <> struct parity<3> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 3, N - 2, N - 1> {}; };
87  template <> struct parity<4> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 4, N - 3, N - 2, N - 1> {}; };
88  template <> struct parity<5> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 5, N - 4, N - 3, N - 2, N - 1> {}; };
89  template <> struct parity<6> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 6, N - 5, N - 4, N - 3, N - 2, N - 1> {}; };
90  template <> struct parity<7> { template <std::size_t N> struct pmake:repeat<typename make<N / 8>::type, N - 7, N - 6, N - 5, N - 4, N - 3, N - 2, N - 1> {}; };
91 
92  template <typename T, typename U>
93  struct convert
94  {
95  template <typename>
96  struct result;
97 
98  template <T ...N>
99  struct result<integer_sequence<T, N...> >
100  {
101  typedef integer_sequence<U, N...> type;
102  };
103  };
104 
105  template <typename T>
106  struct convert<T, T>
107  {
108  template <typename U>
109  struct result
110  {
111  typedef U type;
112  };
113  };
114 
115  template <typename T, T N>
116  using make_integer_sequence_unchecked = typename convert<std::size_t, T>::template result<typename make<N>::type>::type;
117 
118  template <typename T, T N>
119  struct make_integer_sequence
120  {
121  static_assert(std::is_integral<T>::value, "std::make_integer_sequence can only be instantiated with an integral type");
122  static_assert(0 <= N,"std::make_integer_sequence input shall not be negative");
123 
124  typedef make_integer_sequence_unchecked<T, N> type;
125  };
126  }
127 
128  template <typename T, T N>
129  using make_integer_sequence = typename integer_sequence_detail::make_integer_sequence<T, N>::type;
130 
131  template<std::size_t N>
132  using make_index_sequence = make_integer_sequence<std::size_t, N>;
133 
134  template<class... T>
135  using index_sequence_for = make_index_sequence<sizeof...(T)>;
136  #else
137  using std::index_sequence;
138  using std::index_sequence_for;
139  #endif
140 
141  #ifdef TGUI_USE_CPP17
142  using std::void_t;
143  #else
144  // void_t only exists in c++17 so we use our own implementation to support c++14 compilers
145  template<typename...>
146  using void_t = void;
147  #endif
148 
149  // Type to pass a list of template types
150  template <typename...>
151  struct TypeSet;
152 
153  // The dereference function turns the void* elements in the parameters list back into its original type right before calling the signal handler
154 #ifdef TGUI_USE_CPP17
155  template <typename Type>
156  decltype(auto) dereference(const void* obj)
157  {
158  if constexpr (std::is_same_v<Type, std::string>) // Signal handlers are allowed to have std::string parameters while the signal sends sf::String
159  return static_cast<std::string>(*static_cast<const sf::String*>(obj));
160  else if constexpr (std::is_same_v<Type, sf::Vector2f>) // Signal handlers are allowed to have sf::Vector2f parameters while the signal sends tgui::Vector2f
161  return static_cast<sf::Vector2f>(*static_cast<const Vector2f*>(obj));
162  else
163  return *static_cast<const std::decay_t<Type>*>(obj);
164  }
165 #else
166  template <typename Type, typename std::enable_if<std::is_same<Type, std::string>::value>::type* = nullptr>
167  #ifdef TGUI_NO_CPP14
168  std::string dereference(const void* obj)
169  #else
170  decltype(auto) dereference(const void* obj)
171  #endif
172  {
173  // Signal handlers are allowed to have std::string parameters while the signal sends sf::String
174  return static_cast<std::string>(*static_cast<const sf::String*>(obj));
175  }
176 
177  template <typename Type, typename std::enable_if<std::is_same<Type, sf::Vector2f>::value>::type* = nullptr>
178  #ifdef TGUI_NO_CPP14
179  sf::Vector2f dereference(const void* obj)
180  #else
181  decltype(auto) dereference(const void* obj)
182  #endif
183  {
184  // Signal handlers are allowed to have sf::Vector2f parameters while the signal sends tgui::Vector2f
185  return static_cast<sf::Vector2f>(*static_cast<const Vector2f*>(obj));
186  }
187 
188  template <typename Type, typename std::enable_if<!std::is_same<Type, std::string>::value && !std::is_same<Type, sf::Vector2f>::value>::type* = nullptr>
189  #ifdef TGUI_NO_CPP14
190  const Type& dereference(const void* obj)
191  #else
192  decltype(auto) dereference(const void* obj)
193  #endif
194  {
195  return *static_cast<const typename std::decay<Type>::type*>(obj);
196  }
197 #endif
198 
199  #ifndef TGUI_USE_CPP17
200  // std::invoke only exists in c++17 so we use our own implementation to support c++14 compilers
201  // Visual Studio compiler did not like it when the function was called "invoke"
202  template <typename Func, typename... Args, typename std::enable_if<std::is_member_pointer<typename std::decay<Func>::type>::value>::type* = nullptr>
203  void invokeFunc(Func&& func, Args&&... args)
204  {
205  std::mem_fn(func)(std::forward<Args>(args)...);
206  }
207 
208  template <typename Func, typename... Args, typename std::enable_if<!std::is_member_pointer<typename std::decay<Func>::type>::value>::type* = nullptr>
209  void invokeFunc(Func&& func, Args&&... args)
210  {
211  std::forward<Func>(func)(std::forward<Args>(args)...);
212  }
213  #endif
214 
215  // The binder will figure out the unbound parameters and bind them if they correspond to what the signal sends
216  template <typename... Args>
217  struct binder;
218 
219  template <typename Arg, typename... AllArgs, typename BoundArg, typename... BoundArgs>
220  struct binder<TypeSet<Arg, AllArgs...>, TypeSet<BoundArg, BoundArgs...>>
221  : binder<TypeSet<AllArgs...>, TypeSet<BoundArgs...>>
222  {
223  };
224 
225  template <typename... UnboundArgs>
226  struct binder<TypeSet<std::shared_ptr<Widget>, std::string, UnboundArgs...>, TypeSet<>>
227  {
228  template <typename Func, typename... BoundArgs>
229  #ifdef TGUI_NO_CPP14
230  static std::function<void(const std::shared_ptr<Widget>& widget, const std::string& signalName)> bind(Signal& signal, Func&& func, BoundArgs&&... args)
231  #else
232  static decltype(auto) bind(Signal& signal, Func&& func, BoundArgs&&... args)
233  #endif
234  {
235  return bindImpl(index_sequence_for<UnboundArgs...>{}, signal, std::forward<Func>(func), std::forward<BoundArgs>(args)...);
236  }
237 
238  private:
239 
240  template <typename Func, typename... BoundArgs, std::size_t... Indices>
241  #ifdef TGUI_NO_CPP14
242  static std::function<void(const std::shared_ptr<Widget>& widget, const std::string& signalName)> bindImpl(index_sequence<Indices...>, Signal& signal, Func&& func, BoundArgs&&... args)
243  #else
244  static decltype(auto) bindImpl(index_sequence<Indices...>, Signal& signal, Func&& func, BoundArgs&&... args)
245  #endif
246  {
247  const std::size_t offset = (sizeof...(UnboundArgs) > 0) ? signal.validateTypes({typeid(UnboundArgs)...}) : 0;
248  #ifdef TGUI_NO_CPP14
249  return [=](const std::shared_ptr<Widget>& widget, const std::string& signalName) {
250  auto f = func;
251  invokeFunc(f,
252  #elif defined TGUI_USE_CPP17
253  return [=](const std::shared_ptr<Widget>& widget, const std::string& signalName) {
254  std::invoke(func,
255  #else
256  return [=, f=func](const std::shared_ptr<Widget>& widget, const std::string& signalName) { // f=func is needed to decay free functions
257  invokeFunc(f,
258  #endif
259  args...,
260  widget,
261  signalName,
262  internal_signal::dereference<UnboundArgs>(internal_signal::parameters[offset + Indices])...);
263  };
264  }
265  };
266 
267  template <typename... UnboundArgs>
268  struct binder<TypeSet<UnboundArgs...>, TypeSet<>>
269  {
270  template <typename Func, typename... BoundArgs>
271  #ifdef TGUI_NO_CPP14
272  static std::function<void()> bind(Signal& signal, Func&& func, BoundArgs&&... args)
273  #else
274  static decltype(auto) bind(Signal& signal, Func&& func, BoundArgs&&... args)
275  #endif
276  {
277  return bindImpl(index_sequence_for<UnboundArgs...>{}, signal, std::forward<Func>(func), std::forward<BoundArgs>(args)...);
278  }
279 
280  private:
281 
282  template <typename Func, typename... BoundArgs, std::size_t... Indices>
283  #ifdef TGUI_NO_CPP14
284  static std::function<void()> bindImpl(index_sequence<Indices...>, Signal& signal, Func&& func, BoundArgs&&... args)
285  #else
286  static decltype(auto) bindImpl(index_sequence<Indices...>, Signal& signal, Func&& func, BoundArgs&&... args)
287  #endif
288  {
289  const std::size_t offset = (sizeof...(UnboundArgs) > 0) ? signal.validateTypes({typeid(UnboundArgs)...}) : 0;
290  #ifdef TGUI_NO_CPP14
291  return [=]() {
292  auto f = func;
293  invokeFunc(f,
294  #elif defined TGUI_USE_CPP17
295  return [=]() {
296  std::invoke(func,
297  #else
298  return [=, f=func]() { // f=func is needed to decay free functions
299  invokeFunc(f,
300  #endif
301  args...,
302  internal_signal::dereference<UnboundArgs>(internal_signal::parameters[offset + Indices])...);
303  };
304  }
305  };
306 
307 
308  #ifdef TGUI_USE_CPP17
309  // Error case (function signature did not match anything)
310  template <typename Enable, typename Func, typename... BoundArgs>
311  struct func_traits;
312 
313  // Free function
314  template <typename... Args, typename... BoundArgs>
315  struct func_traits<void, void(*)(Args...), BoundArgs...> : binder<TypeSet<std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
316  template <typename... Args, typename... BoundArgs>
317  struct func_traits<void, void(*)(Args...) noexcept, BoundArgs...> : binder<TypeSet<std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
318 
319  // Non-const member function
320  template <typename Class, typename... Args, typename... BoundArgs>
321  struct func_traits<void, void(Class::*)(Args...), BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
322  template <typename Class, typename... Args, typename... BoundArgs>
323  struct func_traits<void, void(Class::*)(Args...) noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
324  template <typename Class, typename... Args, typename... BoundArgs>
325  struct func_traits<void, void(Class::*)(Args...) volatile, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
326  template <typename Class, typename... Args, typename... BoundArgs>
327  struct func_traits<void, void(Class::*)(Args...) volatile noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
328  template <typename Class, typename... Args, typename... BoundArgs>
329  struct func_traits<void, void(Class::*)(Args...) &, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
330  template <typename Class, typename... Args, typename... BoundArgs>
331  struct func_traits<void, void(Class::*)(Args...) & noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
332  template <typename Class, typename... Args, typename... BoundArgs>
333  struct func_traits<void, void(Class::*)(Args...) volatile &, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
334  template <typename Class, typename... Args, typename... BoundArgs>
335  struct func_traits<void, void(Class::*)(Args...) volatile & noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
336  template <typename Class, typename... Args, typename... BoundArgs>
337  struct func_traits<void, void(Class::*)(Args...) &&, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
338  template <typename Class, typename... Args, typename... BoundArgs>
339  struct func_traits<void, void(Class::*)(Args...) && noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
340  template <typename Class, typename... Args, typename... BoundArgs>
341  struct func_traits<void, void(Class::*)(Args...) volatile &&, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
342  template <typename Class, typename... Args, typename... BoundArgs>
343  struct func_traits<void, void(Class::*)(Args...) volatile && noexcept, BoundArgs...> : binder<TypeSet<Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
344 
345  // Const member function
346  template <typename Class, typename... Args, typename... BoundArgs>
347  struct func_traits<void, void(Class::*)(Args...) const, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
348  template <typename Class, typename... Args, typename... BoundArgs>
349  struct func_traits<void, void(Class::*)(Args...) const noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
350  template <typename Class, typename... Args, typename... BoundArgs>
351  struct func_traits<void, void(Class::*)(Args...) volatile const, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
352  template <typename Class, typename... Args, typename... BoundArgs>
353  struct func_traits<void, void(Class::*)(Args...) volatile const noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
354  template <typename Class, typename... Args, typename... BoundArgs>
355  struct func_traits<void, void(Class::*)(Args...) const &, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
356  template <typename Class, typename... Args, typename... BoundArgs>
357  struct func_traits<void, void(Class::*)(Args...) const & noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
358  template <typename Class, typename... Args, typename... BoundArgs>
359  struct func_traits<void, void(Class::*)(Args...) volatile const &, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
360  template <typename Class, typename... Args, typename... BoundArgs>
361  struct func_traits<void, void(Class::*)(Args...) volatile const & noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
362  template <typename Class, typename... Args, typename... BoundArgs>
363  struct func_traits<void, void(Class::*)(Args...) const &&, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
364  template <typename Class, typename... Args, typename... BoundArgs>
365  struct func_traits<void, void(Class::*)(Args...) const && noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
366  template <typename Class, typename... Args, typename... BoundArgs>
367  struct func_traits<void, void(Class::*)(Args...) volatile const &&, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
368  template <typename Class, typename... Args, typename... BoundArgs>
369  struct func_traits<void, void(Class::*)(Args...) volatile const && noexcept, BoundArgs...> : binder<TypeSet<const Class*, std::decay_t<Args>...>, TypeSet<BoundArgs...>> {};
370 
371  // std::function or lambda
372  template <typename Func, typename... BoundArgs>
373  struct func_traits<void_t<decltype(&Func::operator())>, Func, BoundArgs...> : public func_traits<void, decltype(&Func::operator()), Func*, BoundArgs...> {};
374  #else
375  // Error case (function signature did not match anything)
376  template <typename Enable, typename Func, typename... BoundArgs>
377  struct func_traits;
378 
379  // std::function or lambda
380  template <typename Func, typename... BoundArgs>
381  struct func_traits<void_t<decltype(&Func::operator())>, Func, BoundArgs...>
382  : public func_traits<void, decltype(&Func::operator()), Func*, BoundArgs...>
383  {
384  };
385 
386  // Non-const member function
387  template <typename Class, typename... Args, typename... BoundArgs>
388  struct func_traits<void, void(Class::*)(Args...), BoundArgs...>
389  : binder<TypeSet<Class*, typename std::decay<Args>::type...>, TypeSet<BoundArgs...>>
390  {
391  };
392 
393  // Const member function
394  template <typename Class, typename... Args, typename... BoundArgs>
395  struct func_traits<void, void(Class::*)(Args...) const, BoundArgs...>
396  : binder<TypeSet<const Class*, typename std::decay<Args>::type...>, TypeSet<BoundArgs...>>
397  {
398  };
399 
400  // Free function
401  template <typename... Args, typename... BoundArgs>
402  struct func_traits<void, void(*)(Args...), BoundArgs...>
403  : binder<TypeSet<typename std::decay<Args>::type...>, TypeSet<BoundArgs...>>
404  {
405  };
406  #endif
407  }
408 
410 
411 #ifdef TGUI_USE_CPP17
412  template <typename Func, typename... BoundArgs>
413  unsigned int SignalWidgetBase::connect(std::string signalName, Func&& handler, const BoundArgs&... args)
414  {
415  unsigned int id;
416  Signal& signal = getSignal(toLower(signalName));
417 
418  if constexpr (std::is_convertible_v<Func, std::function<void(const BoundArgs&...)>>
419  && std::is_invocable_v<decltype(&handler), BoundArgs...>
420  && !std::is_function_v<Func>)
421  {
422  // Reference to function, all parameters bound
423  id = signal.connect([=, f=std::function<void(const BoundArgs&...)>(handler)]{ std::invoke(f, args...); });
424  }
425  else if constexpr (std::is_convertible_v<Func, std::function<void(const BoundArgs&...)>>)
426  {
427  // Function with all parameters bound
428  id = signal.connect([=]{ std::invoke(handler, args...); });
429  }
430  else if constexpr (std::is_convertible_v<Func, std::function<void(const BoundArgs&..., const std::shared_ptr<Widget>&, const std::string&)>>
431  && std::is_invocable_v<decltype(&handler), BoundArgs..., const std::shared_ptr<Widget>&, const std::string&>
432  && !std::is_function_v<Func>)
433  {
434  // Reference to function with caller arguments, all parameters bound
435  id = signal.connect([=, f=std::function<void(const BoundArgs&..., const std::shared_ptr<Widget>& w, const std::string& s)>(handler)](const std::shared_ptr<Widget>& w, const std::string& s){ std::invoke(f, args..., w, s); });
436  }
437  else if constexpr (std::is_convertible_v<Func, std::function<void(const BoundArgs&..., const std::shared_ptr<Widget>&, const std::string&)>>)
438  {
439  // Function with caller arguments, all parameters bound
440  id = signal.connect([=](const std::shared_ptr<Widget>& w, const std::string& s){ std::invoke(handler, args..., w, s); });
441  }
442  else
443  {
444  // Function with unbound arguments
445  using binder = internal_signal::func_traits<void, std::decay_t<Func>, BoundArgs...>;
446  id = signal.connect(binder::bind(signal, std::forward<Func>(handler), args...));
447  }
448 
449  m_connectedSignals[id] = toLower(signalName);
450  return id;
451  }
452 
453 #else
454  template <typename Func, typename... Args, typename std::enable_if<std::is_convertible<Func, std::function<void(const Args&...)>>::value>::type*>
455  unsigned int SignalWidgetBase::connect(std::string signalName, Func&& handler, const Args&... args)
456  {
457  #ifdef TGUI_NO_CPP14
458  const unsigned int id = getSignal(toLower(signalName)).connect([=](){ (std::function<void(const Args&...)>(handler))(args...); });
459  #else
460  const unsigned int id = getSignal(toLower(signalName)).connect([f=std::function<void(const Args&...)>(handler),args...](){ f(args...); });
461  #endif
462  m_connectedSignals[id] = toLower(signalName);
463  return id;
464  }
465 
466  template <typename Func, typename... BoundArgs, typename std::enable_if<std::is_convertible<Func, std::function<void(const BoundArgs&..., std::shared_ptr<Widget>, const std::string&)>>::value>::type*>
467  unsigned int SignalWidgetBase::connect(std::string signalName, Func&& handler, BoundArgs&&... args)
468  {
469  #ifdef TGUI_NO_CPP14
470  const unsigned int id = getSignal(toLower(signalName)).connect(
471  [=](const std::shared_ptr<Widget>& w, const std::string& s) {
472  (std::function<void(const BoundArgs&..., const std::shared_ptr<Widget>&, const std::string&)>(handler))(args..., w, s);
473  }
474  );
475  #else
476  const unsigned int id = getSignal(toLower(signalName)).connect(
477  [f=std::function<void(const BoundArgs&..., const std::shared_ptr<Widget>&, const std::string&)>(handler), args...]
478  (const std::shared_ptr<Widget>& w, const std::string& s)
479  { f(args..., w, s); }
480  );
481  #endif
482 
483  m_connectedSignals[id] = toLower(signalName);
484  return id;
485  }
486 
487  template <typename Func, typename... BoundArgs, typename std::enable_if<!std::is_convertible<Func, std::function<void(const BoundArgs&...)>>::value
488  && !std::is_convertible<Func, std::function<void(const BoundArgs&..., std::shared_ptr<Widget>, const std::string&)>>::value>::type*>
489  unsigned int SignalWidgetBase::connect(std::string signalName, Func&& handler, BoundArgs&&... args)
490  {
491  Signal& signal = getSignal(toLower(signalName));
492  using binder = internal_signal::func_traits<void, typename std::decay<Func>::type, BoundArgs...>;
493  const unsigned int id = signal.connect(binder::bind(signal, std::forward<Func>(handler), std::forward<BoundArgs>(args)...));
494  m_connectedSignals[id] = toLower(signalName);
495  return id;
496  }
497 #endif
498 
500 
501  template <typename Func, typename... BoundArgs>
502  unsigned int SignalWidgetBase::connect(std::initializer_list<std::string> signalNames, Func&& handler, BoundArgs&&... args)
503  {
504  unsigned int lastId = 0;
505  for (auto& signalName : signalNames)
506  lastId = connect(std::move(signalName), handler, args...);
507 
508  return lastId;
509  }
510 }
511 
513 
514 #endif // TGUI_SIGNAL_IMPL_HPP
Namespace that contains all TGUI functions and classes.
Definition: AbsoluteOrRelativeValue.hpp:36
unsigned int connect(std::string signalName, Func &&handler, const Args &... args)
Connects a signal handler that will be called when this signal is emitted.
Definition: SignalImpl.hpp:455
Signal to which the user can subscribe to get callbacks from.
Definition: Signal.hpp:58
unsigned int connect(const Delegate &handler)
Connects a signal handler that will be called when this signal is emitted.