26#ifndef TGUI_SIGNAL_HPP
27#define TGUI_SIGNAL_HPP
30#include <TGUI/Global.hpp>
31#include <TGUI/Callback.hpp>
48 template <
typename... Types>
55 extern TGUI_API std::deque<const void*> data;
60 std::string convertTypeToString();
62 template <>
inline std::string convertTypeToString<int>() {
return "int"; }
63 template <>
inline std::string convertTypeToString<sf::Vector2f>() {
return "sf::Vector2f"; }
64 template <>
inline std::string convertTypeToString<sf::String>() {
return "sf::String"; }
65 template <>
inline std::string convertTypeToString<std::vector<sf::String>>() {
return "std::vector<sf::String>"; }
66 template <>
inline std::string convertTypeToString<std::shared_ptr<ChildWindow>>() {
return "std::shared_ptr<ChildWindow>"; }
70 template <
typename... Types>
73 static std::vector<std::vector<std::string>> get() {
return {}; }
74 static std::vector<std::string> getRow() {
return {}; }
77 template <
typename Type>
78 struct extractTypes<Type>
80 static std::vector<std::vector<std::string>> get() {
return {{convertTypeToString<Type>()}}; }
81 static std::vector<std::string> getRow() {
return {convertTypeToString<Type>()}; }
84 template <
typename Type,
typename... OtherTypes>
85 struct extractTypes<Type, OtherTypes...>
87 static std::vector<std::vector<std::string>> get()
89 auto types = extractTypes<OtherTypes...>::get();
90 types.insert(types.begin(), {convertTypeToString<Type>()});
94 static std::vector<std::string> getRow()
96 auto types = extractTypes<OtherTypes...>::getRow();
97 types.insert(types.begin(), convertTypeToString<Type>());
102 template <
typename... T>
103 struct extractTypes<TypeSet<T...>>
105 static std::vector<std::vector<std::string>> get() {
return {extractTypes<T...>::getRow()}; }
108 template <
typename... T,
typename... U>
109 struct extractTypes<TypeSet<T...>, U...>
111 static std::vector<std::vector<std::string>> get()
113 auto types = {extractTypes<T...>::getRow()};
114 types.insert(types.end(), extractTypes<U...>::get());
121 template <
typename Func,
typename TypeA,
typename TypeB,
typename... Args>
122 struct isConvertible;
124 template <
typename Func,
typename... TypesA,
typename... TypesB,
typename... Args>
125 struct isConvertible<Func, TypeSet<TypesA...>, TypeSet<TypesB...>, Args...>
127 using type =
typename std::conditional<std::is_convertible<Func, std::function<void(Args..., TypesA...)>>::value, TypeSet<TypesA...>, TypeSet<TypesB...>>::type;
130 template <
typename Func,
typename... Type,
typename... Args>
131 struct isConvertible<Func, TypeSet<>, TypeSet<Type...>, Args...>
133 using type =
typename std::conditional<std::is_convertible<Func, std::function<void(Args...)>>::value || std::is_convertible<Func, std::function<void(Args...)>>::value, TypeSet<>, TypeSet<Type...>>::type;
138 template <
typename Type>
139 const Type& dereference(
const void* obj)
141 return *
static_cast<const Type*
>(obj);
147#if defined SFML_SYSTEM_WINDOWS && defined _MSC_VER
148 #pragma warning(push)
149 #pragma warning(disable : 4800)
152 template <
typename... T>
155 template <
typename Func,
typename... Args>
156 struct connector<TypeSet<>, Func, Args...>
158 static std::function<void()> connect(Func func, std::size_t, Args... args)
160 return std::bind(func, args...);
164 template <
typename Func,
typename... Args,
typename Type>
165 struct connector<TypeSet<Type>, Func, Args...>
167 static std::function<void()> connect(Func func, std::size_t argPos, Args... args)
169 return std::bind(func, args..., std::bind(dereference<Type>, std::cref(data[argPos])));
173 template <
typename Func,
typename... Args,
typename TypeA,
typename TypeB>
174 struct connector<TypeSet<TypeA, TypeB>, Func, Args...>
176 static std::function<void()> connect(Func func, std::size_t argPos, Args... args)
178 return std::bind(func, args...,
179 std::bind(dereference<TypeA>, std::cref(data[argPos])),
180 std::bind(dereference<TypeB>, std::cref(data[argPos+1])));
184#if defined SFML_SYSTEM_WINDOWS && defined _MSC_VER
190 template <
typename Arg,
typename =
void>
193 static Arg remove(Arg arg)
199 template <
typename Arg>
200 struct bindRemover<Arg, typename std::enable_if<std::is_bind_expression<Arg>::value>::type>
202 static auto remove(Arg arg) ->
decltype(arg())
210 template <
typename Func,
typename... Args>
211 struct isFunctionConvertible
213 using type =
typename isConvertible<Func, TypeSet<>,
214 typename isConvertible<Func, TypeSet<int>,
215 typename isConvertible<Func, TypeSet<sf::Vector2f>,
216 typename isConvertible<Func, TypeSet<sf::String>,
217 typename isConvertible<Func, TypeSet<std::vector<sf::String>>,
218 typename isConvertible<Func, TypeSet<std::shared_ptr<ChildWindow>>,
219 typename isConvertible<Func, TypeSet<sf::String, sf::String>,
242 Signal(std::vector<std::vector<std::string>>&& types);
244 template <
typename Func,
typename... Args>
245 void connect(
unsigned int id, Func func, Args... args)
247 using type =
typename priv::isFunctionConvertible<Func,
decltype(priv::bindRemover<Args>::remove(args))...>::type;
248 static_assert(!std::is_same<type, TypeSet<void>>::value,
"Parameters passed to the connect function are wrong!");
250 auto argPos = checkCompatibleParameterType<type>();
251 m_functions[id] = priv::connector<type, Func, Args...>::connect(func, argPos, args...);
254 template <
typename Func,
typename... Args>
255 void connectEx(
unsigned int id, Func func, Args... args)
257 m_functionsEx[id] = std::bind(func, args..., std::placeholders::_1);
260 bool disconnect(
unsigned int id);
262 void disconnectAll();
264 bool isEmpty()
const;
266 void operator()(
unsigned int count);
268 template <
typename T,
typename... Args>
269 void operator()(
unsigned int count,
const T& value, Args... args)
271 priv::data[count] =
static_cast<const void*
>(&value);
272 (*this)(count+1, args...);
277 template <
typename Type>
278 std::size_t checkCompatibleParameterType()
280 if (std::is_same<Type, TypeSet<>>::value)
283 auto acceptedType = priv::extractTypes<Type>::get();
284 assert(acceptedType.size() == 1);
286 std::size_t count = 0;
287 for (std::size_t i = 0; i < m_allowedTypes.size(); ++i)
289 if (acceptedType[0] == m_allowedTypes[i])
292 count += m_allowedTypes[i].size();
295 throw Exception{
"Failed to bind parameter to callback function. Parameter is of wrong type."};
300 std::map<
unsigned int, std::function<void()>> m_functions;
301 std::map<
unsigned int, std::function<void(
const Callback&)>> m_functionsEx;
303 std::vector<std::vector<std::string>> m_allowedTypes;
353 template <
typename Func,
typename... Args>
354 unsigned int connect(
const std::string& signalNames, Func func, Args... args)
356 auto signalNameList = extractSignalNames(signalNames);
357 if (signalNameList.empty())
358 throw Exception{
"connect function called with empty string"};
360 for (
auto& signalName : signalNameList)
362 if (m_signals.find(toLower(signalName)) != m_signals.end())
365 m_signals[toLower(signalName)]->connect(m_lastId, func, args...);
369 throw Exception{e.what() + (
" The parameters are not valid for the '" + signalName +
"' signal.")};
374 if (toLower(signalName) !=
"all")
375 throw Exception{
"Cannot connect to unknown signal '" + signalName +
"'."};
378 assert(!m_signals.empty());
380 for (
auto& signal : m_signals)
383 signal.second->connect(m_lastId, func, args...);
387 throw Exception{e.what() + (
" The parameters are not valid for the '" + signalName +
"' signal.")};
410 template <
typename Func,
typename... Args>
411 unsigned int connectEx(
const std::string& signalName, Func func, Args... args)
413 auto signalNameList = extractSignalNames(signalName);
414 if (signalNameList.empty())
415 throw Exception{
"connect function called with empty string"};
417 for (
auto& name : signalNameList)
419 if (m_signals.find(toLower(name)) != m_signals.end())
422 m_signals[toLower(name)]->connectEx(m_lastId, func, args...);
426 throw Exception{e.what() + (
" since it is not valid for the '" + name +
"' signal.")};
431 if (toLower(name) !=
"all")
432 throw Exception{
"Cannot connect to unknown signal '" + name +
"'."};
435 assert(!m_signals.empty());
437 for (
auto& signal : m_signals)
440 signal.second->connectEx(m_lastId, func, args...);
444 throw Exception{e.what() + (
" since it is not valid for the '" + name +
"' signal.")};
487 template <
typename... T>
488 void addSignal(std::string&& name)
490 assert(m_signals[toLower(name)] ==
nullptr);
491 m_signals[toLower(name)] = std::make_shared<Signal>(priv::extractTypes<T...>::get());
498 bool isSignalBound(std::string&& name);
504 template <
typename... Args>
505 void sendSignal(std::string&& name, Args... args)
507 assert(m_signals[toLower(name)] !=
nullptr);
508 auto& signal = *m_signals[toLower(name)];
510 if (signal.m_functionsEx.empty())
512 if (!signal.isEmpty())
518 Signal signalCopy = signal;
520 m_callback.trigger = name;
521 for (
const auto&
function : signalCopy.m_functionsEx)
522 function.second(m_callback);
524 if (!signalCopy.isEmpty())
525 signalCopy(0, args...);
533 std::vector<std::string> extractSignalNames(std::string input);
538 std::map<std::string, std::shared_ptr<Signal>> m_signals;
540 static unsigned int m_lastId;
Definition: Exception.hpp:44
Definition: Signal.hpp:239
Namespace that contains all TGUI functions and classes.
Definition: Animation.hpp:34
Definition: Callback.hpp:45