TGUI  0.8-alpha
Signal.hpp
1 //
3 // TGUI - Texus' Graphical User Interface
4 // Copyright (C) 2012-2018 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_HPP
27 #define TGUI_SIGNAL_HPP
28 
30 
31 #include <TGUI/Global.hpp>
32 #include <TGUI/Vector2f.hpp>
33 #include <SFML/System/String.hpp>
34 #include <functional>
35 #include <typeindex>
36 #include <memory>
37 #include <vector>
38 #include <deque>
39 #include <map>
40 
42 
43 namespace tgui
44 {
45  class Widget;
46  class ChildWindow;
47  class SignalWidgetBase;
48 
49  namespace internal_signal
50  {
51  extern TGUI_API std::deque<const void*> parameters;
52  }
53 
54 
58  class TGUI_API Signal
59  {
60  public:
61 
62  using Delegate = std::function<void()>;
63  using DelegateEx = std::function<void(std::shared_ptr<Widget>, const std::string&)>;
64 
65 
66  virtual ~Signal() = default;
67 
68 
75  Signal(std::string&& name, std::size_t extraParameters = 0) :
76  m_name{std::move(name)}
77  {
78  if (1 + extraParameters > internal_signal::parameters.size())
79  internal_signal::parameters.resize(1 + extraParameters);
80  }
81 
82 
86  Signal(const Signal& other);
87 
88 
92  Signal(Signal&& other) = default;
93 
94 
98  Signal& operator=(const Signal& other);
99 
100 
104  Signal& operator=(Signal&& other) = default;
105 
106 
114  unsigned int connect(const Delegate& handler);
115 
116 
124  unsigned int connect(const DelegateEx& handler);
125 
126 
134  bool disconnect(unsigned int id);
135 
136 
140  void disconnectAll();
141 
142 
150  bool emit(const Widget* widget)
151  {
152  if (m_handlers.empty())
153  return false;
154 
155  internal_signal::parameters[0] = static_cast<const void*>(&widget);
156 
157  // Copy the handlers before calling them in case the widget (and this signal) gets destroyed during the handler
158  auto handlers = m_handlers;
159  for (auto& handler : handlers)
160  handler.second();
161 
162  return true;
163  }
164 
165 
171  std::string getName() const
172  {
173  return m_name;
174  }
175 
176 
182  virtual unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters);
183 
184 
186  protected:
187 
192  static std::shared_ptr<Widget> getWidget();
193 
194 
196  protected:
197 
198  std::string m_name;
199  std::map<unsigned int, std::function<void()>> m_handlers;
200  };
201 
202 
203  #define TGUI_SIGNAL_VALUE_DECLARATION(TypeName, Type) \
204  /**************************************************************************************************************************** \
205  * @brief Signal to which the user can subscribe to get callbacks from
206  ****************************************************************************************************************************/ \
207  class TGUI_API Signal##TypeName : public Signal \
208  { \
209  public: \
210  using Delegate##TypeName = std::function<void(Type)>; \
211  using Delegate##TypeName##Ex = std::function<void(std::shared_ptr<Widget>, const std::string&, Type)>; \
212  using Signal::connect; \
213  \
214  /************************************************************************************************************************ \
215  * @brief Constructor
216  ************************************************************************************************************************/ \
217  Signal##TypeName(std::string&& name) : \
218  Signal{std::move(name), 1} \
219  { \
220  } \
221  \
222  /************************************************************************************************************************ \
223  * @brief Connects a signal handler that will be called when this signal is emitted
224  *
225  * @param handler Callback function that is given a Vector2f as argument
226  *
227  * @return Unique id of the connection
228  ************************************************************************************************************************/ \
229  unsigned int connect(const Delegate##TypeName& handler); \
230  \
231  /************************************************************************************************************************ \
232  * @brief Connects a signal handler that will be called when this signal is emitted
233  *
234  * @param handler Callback function that is given a pointer to the widget, the name of the signal and a Vector2f as arguments
235  *
236  * @return Unique id of the connection
237  ************************************************************************************************************************/ \
238  unsigned int connect(const Delegate##TypeName##Ex& handler); \
239  \
240  /************************************************************************************************************************ \
241  * @internal
242  * @brief Call all connected signal handlers
243  ************************************************************************************************************************/ \
244  bool emit(const Widget* widget, Type strParam) \
245  { \
246  if (m_handlers.empty()) \
247  return false; \
248  \
249  internal_signal::parameters[1] = static_cast<const void*>(&strParam); \
250  return Signal::emit(widget); \
251  } \
252  \
253  /************************************************************************************************************************ \
254  * @internal
255  * @brief Checks whether the unbound parameters match with this signal
256  * @return The index in the parameters list where the parameters will be stored
257  ************************************************************************************************************************/ \
258  unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters) override; \
259  };
260 
261 
262  TGUI_SIGNAL_VALUE_DECLARATION(Int, int)
263  TGUI_SIGNAL_VALUE_DECLARATION(UInt, unsigned int)
264  TGUI_SIGNAL_VALUE_DECLARATION(Bool, bool)
265  TGUI_SIGNAL_VALUE_DECLARATION(Float, float)
266  TGUI_SIGNAL_VALUE_DECLARATION(String, const sf::String&)
267  TGUI_SIGNAL_VALUE_DECLARATION(Vector2f, Vector2f)
268 
269 
270 
271  class TGUI_API SignalRange : public Signal
274  {
275  public:
276 
277  using DelegateRange = std::function<void(float, float)>;
278  using DelegateRangeEx = std::function<void(std::shared_ptr<Widget>, const std::string&, float, float)>;
279 
280  using Signal::connect;
281 
282 
286  SignalRange(std::string&& name) :
287  Signal{std::move(name), 2}
288  {
289  }
290 
291 
299  unsigned int connect(const DelegateRange& handler);
300 
301 
309  unsigned int connect(const DelegateRangeEx& handler);
310 
311 
316  bool emit(const Widget* widget, float value1, float value2);
317 
318 
324  unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters) override;
325 
326 
328  };
329 
330 
334  class TGUI_API SignalChildWindow : public Signal
335  {
336  public:
337 
338  using DelegateChildWindow = std::function<void(std::shared_ptr<ChildWindow>)>;
339  using DelegateChildWindowEx = std::function<void(std::shared_ptr<Widget>, const std::string&, std::shared_ptr<ChildWindow>)>;
340 
341  using Signal::connect;
342 
343 
347  SignalChildWindow(std::string&& name) :
348  Signal{std::move(name), 1}
349  {
350  }
351 
352 
360  unsigned int connect(const DelegateChildWindow& handler);
361 
362 
370  unsigned int connect(const DelegateChildWindowEx& handler);
371 
372 
377  bool emit(const ChildWindow* param);
378 
379 
385  unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters) override;
386 
387 
389  };
390 
391 
395  class TGUI_API SignalItem : public Signal
396  {
397  public:
398 
399  using DelegateItem = std::function<void(const sf::String&)>;
400  using DelegateItemAndId = std::function<void(const sf::String&, const sf::String&)>;
401  using DelegateItemEx = std::function<void(std::shared_ptr<Widget>, const std::string&, const sf::String&)>;
402  using DelegateItemAndIdEx = std::function<void(std::shared_ptr<Widget>, const std::string&, const sf::String&, const sf::String&)>;
403 
404  using Signal::connect;
405 
406 
410  SignalItem(std::string&& name) :
411  Signal{std::move(name), 2}
412  {
413  }
414 
415 
423  unsigned int connect(const DelegateItem& handler);
424 
425 
433  unsigned int connect(const DelegateItemEx& handler);
434 
435 
443  unsigned int connect(const DelegateItemAndId& handler);
444 
445 
453  unsigned int connect(const DelegateItemAndIdEx& handler);
454 
455 
460  bool emit(const Widget* widget, const sf::String& item, const sf::String& id)
461  {
462  if (m_handlers.empty())
463  return false;
464 
465  internal_signal::parameters[1] = static_cast<const void*>(&item);
466  internal_signal::parameters[2] = static_cast<const void*>(&id);
467  return Signal::emit(widget);
468  }
469 
470 
476  unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters) override;
477 
478 
480  };
481 
482 
486  class TGUI_API SignalMenuItem : public Signal
487  {
488  public:
489 
490  using DelegateMenuItem = std::function<void(const sf::String&)>;
491  using DelegateMenuItemFull = std::function<void(const std::vector<sf::String>&)>;
492  using DelegateMenuItemEx = std::function<void(std::shared_ptr<Widget>, const std::string&, const sf::String&)>;
493  using DelegateMenuItemFullEx = std::function<void(std::shared_ptr<Widget>, const std::string&, const std::vector<sf::String>&)>;
494 
495  using Signal::connect;
496 
497 
501  SignalMenuItem(std::string&& name) :
502  Signal{std::move(name), 2}
503  {
504  }
505 
506 
514  unsigned int connect(const DelegateMenuItem& handler);
515 
516 
524  unsigned int connect(const DelegateMenuItemEx& handler);
525 
526 
534  unsigned int connect(const DelegateMenuItemFull& handler);
535 
536 
544  unsigned int connect(const DelegateMenuItemFullEx& handler);
545 
546 
551  bool emit(const Widget* widget, const sf::String& item, const std::vector<sf::String>& fullItem)
552  {
553  if (m_handlers.empty())
554  return false;
555 
556  internal_signal::parameters[1] = static_cast<const void*>(&item);
557  internal_signal::parameters[2] = static_cast<const void*>(&fullItem);
558  return Signal::emit(widget);
559  }
560 
561 
567  unsigned int validateTypes(std::initializer_list<std::type_index> unboundParameters) override;
568 
569 
571  };
572 
573 
577  class TGUI_API SignalWidgetBase
578  {
579  public:
580 
581  virtual ~SignalWidgetBase() = default;
582 
583 #ifdef TGUI_USE_CPP17
584  template <typename Func, typename... BoundArgs>
594  unsigned int connect(std::string signalName, Func&& handler, const BoundArgs&... args);
595 
596 #else
597  template <typename Func, typename... Args, typename std::enable_if<std::is_convertible<Func, std::function<void(const Args&...)>>::value>::type* = nullptr>
607  unsigned int connect(std::string signalName, Func&& handler, const Args&... args);
608 
609 
620  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* = nullptr>
621  unsigned int connect(std::string signalName, Func&& handler, BoundArgs&&... args);
622 
623 
633  template <typename Func, typename... BoundArgs, typename std::enable_if<!std::is_convertible<Func, std::function<void(const BoundArgs&...)>>::value
634  && !std::is_convertible<Func, std::function<void(const BoundArgs&..., std::shared_ptr<Widget>, const std::string&)>>::value>::type* = nullptr>
635  unsigned int connect(std::string signalName, Func&& handler, BoundArgs&&... args);
636 #endif
637 
647  template <typename Func, typename... BoundArgs>
648  unsigned int connect(std::initializer_list<std::string> signalNames, Func&& handler, BoundArgs&&... args);
649 
650 
658  bool disconnect(unsigned int id);
659 
660 
666  void disconnectAll(std::string signalName);
667 
668 
672  void disconnectAll();
673 
674 
676  protected:
677 
681  virtual Signal& getSignal(std::string signalName) = 0;
682 
683 
685  private:
686 
687  std::map<unsigned int, std::string> m_connectedSignals;
688 
689 
691  };
692 
694 }
695 
697 
698 #endif // TGUI_SIGNAL_HPP
Namespace that contains all TGUI functions and classes.
Definition: AbsoluteOrRelativeValue.hpp:36
The parent class for every widget.
Definition: Widget.hpp:72
SignalChildWindow(std::string &&name)
Constructor.
Definition: Signal.hpp:347
Base class for Widget which provides functionality to connect signals based on their name...
Definition: Signal.hpp:577
bool emit(const Widget *widget)
Call all connected signal handlers.
Definition: Signal.hpp:150
std::string getName() const
Returns the name given to the signal.
Definition: Signal.hpp:171
Signal to which the user can subscribe to get callbacks from.
Definition: Signal.hpp:486
Signal to which the user can subscribe to get callbacks from.
Definition: Signal.hpp:395
SignalRange(std::string &&name)
Constructor.
Definition: Signal.hpp:286
Signal to which the user can subscribe to get callbacks from.
Definition: Signal.hpp:58
Signal to which the user can subscribe to get callbacks from.
Definition: Signal.hpp:334
SignalMenuItem(std::string &&name)
Constructor.
Definition: Signal.hpp:501
unsigned int connect(const Delegate &handler)
Connects a signal handler that will be called when this signal is emitted.
SignalItem(std::string &&name)
Constructor.
Definition: Signal.hpp:410
Signal(std::string &&name, std::size_t extraParameters=0)
Constructor.
Definition: Signal.hpp:75