/*********************************************************************** * fcallback.h - Implements the callback functionality * * * * This file is part of the FINAL CUT widget toolkit * * * * Copyright 2020 Markus Gans * * * * FINAL CUT is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * FINAL CUT is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program. If not, see * * . * ***********************************************************************/ /* Standalone class * ════════════════ * * ▕▔▔▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ * ▕ FCallback ▏- - - -▕ FCallbackData ▏ * ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ */ #ifndef FCALLBACK_H #define FCALLBACK_H #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT) #error "Only can be included directly." #endif #include "final/fstring.h" #include "final/ftypes.h" namespace finalcut { // class forward declaration class FWidget; //---------------------------------------------------------------------- // struct FCallbackData //---------------------------------------------------------------------- struct FCallbackData { // Constructor FCallbackData() { } FCallbackData (const FString& s, FWidget* i, void* m, const FCall& c) : cb_signal(s) , cb_instance(i) , cb_function_ptr(m) , cb_function(c) { } FCallbackData (const FCallbackData& c) // copy constructor : cb_signal(c.cb_signal) , cb_instance(c.cb_instance) , cb_function_ptr(c.cb_function_ptr) , cb_function(c.cb_function) { } FCallbackData (FCallbackData&& c) noexcept // move constructor : cb_signal(std::move(c.cb_signal)) , cb_instance(std::move(c.cb_instance)) , cb_function_ptr(std::move(c.cb_function_ptr)) , cb_function(std::move(c.cb_function)) { } // Destructor ~FCallbackData() { } // Overloaded operators FCallbackData& operator = (const FCallbackData& c) { cb_signal = c.cb_signal; cb_instance = c.cb_instance; cb_function_ptr = c.cb_function_ptr; cb_function = c.cb_function; return *this; } FCallbackData& operator = (FCallbackData&& c) noexcept { cb_signal = std::move(c.cb_signal); cb_instance = std::move(c.cb_instance); cb_function_ptr = std::move(c.cb_function_ptr); cb_function = std::move(c.cb_function); return *this; } // Data members FString cb_signal{}; FWidget* cb_instance{}; void* cb_function_ptr{}; FCall cb_function{}; }; //---------------------------------------------------------------------- // class FCallback //---------------------------------------------------------------------- class FCallback { public: // Constructors FCallback(); // Disable copy constructor FCallback (const FCallback&) = delete; // Destructor ~FCallback(); // Disable copy assignment operator (=) FCallback& operator = (const FCallback&) = delete; // Accessors const FString getClassName() const { return "FCallback"; } std::size_t getCallbackCount() { return callback_objects.size(); } // Methods template::value && ! std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value && std::is_member_function_pointer::value && ! std::is_function::type>::value && ! std::is_function::value && ! std::is_pointer::value && std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Object&& cb_instance , Function&& cb_member , Args&&... args) { // Add a member function pointer as callback Object instance = cb_instance; auto member = reinterpret_cast(std::addressof(cb_member)); auto fn = std::bind ( std::forward(cb_member) , std::forward(cb_instance) , std::forward(args)... ); FCallbackData obj{ cb_signal, instance, member, fn }; callback_objects.push_back(obj); } template::value && ! std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value && ! std::is_member_function_pointer::value && ! std::is_function::type>::value && ! std::is_function::value && ! std::is_pointer::value && std::is_object::value && std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Object&& cb_instance , Function&& cb_function , Args&&... args) { // Add a function object to an instance as callback auto fn = std::bind (std::forward(cb_function), std::forward(args)...); FCallbackData obj{ cb_signal, cb_instance, nullptr, fn }; callback_objects.push_back(obj); } template::value && ! std::is_function::type>::value && ! std::is_function::value && ! std::is_pointer::value && std::is_object::value && std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function&& cb_function , Args&&... args) { // Add a function object as callback auto fn = std::bind ( std::forward(cb_function) , std::forward(args)... ); FCallbackData obj{ cb_signal, nullptr, nullptr, fn }; callback_objects.push_back(obj); } template::value && std::is_function::type>::value && std::is_function::value && ! std::is_pointer::value && ! std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function& cb_function , Args&&... args) { // Add a function as callback auto ptr = reinterpret_cast(&cb_function); auto fn = std::bind ( std::forward(cb_function) , std::forward(args)... ); FCallbackData obj{ cb_signal, nullptr, ptr, fn }; callback_objects.push_back(obj);; } template::value && std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function&& cb_function , Args&&... args) { // Add a function pointer as callback auto ptr = reinterpret_cast(cb_function); auto fn = std::bind ( std::forward(cb_function) , std::forward(args)... ); FCallbackData obj{ cb_signal, nullptr, ptr, fn }; callback_objects.push_back(obj); } template::value && ! std::is_function::type>::value && ! std::is_function::value && ! std::is_pointer::value && std::is_object::value && std::is_class::value , std::nullptr_t >::type = nullptr , typename... Args> void addCallback ( const FString& cb_signal , Function& cb_function , Args&&... args) { // Add a non-union class type as callback auto fn = std::bind ( std::forward(cb_function) , std::forward(args)... ); FCallbackData obj{ cb_signal, nullptr, nullptr, fn }; callback_objects.push_back(obj); } template::value && ! std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr > void delCallback (Object&& cb_instance) { // Deletes entries with the given instance from the callback list if ( callback_objects.empty() ) return; auto iter = callback_objects.begin(); while ( iter != callback_objects.end() ) { if ( iter->cb_instance == cb_instance ) iter = callback_objects.erase(iter); else ++iter; } } void delCallback (const FString& cb_signal) { // Deletes entries with the given signal from the callback list if ( callback_objects.empty() ) return; auto iter = callback_objects.begin(); while ( iter != callback_objects.end() ) { if ( iter->cb_signal == cb_signal ) iter = callback_objects.erase(iter); else ++iter; } } template::value && ! std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr > void delCallback (const FString& cb_signal, Object&& cb_instance) { // Deletes entries with the given signal and instance // from the callback list if ( callback_objects.empty() ) return; auto iter = callback_objects.begin(); while ( iter != callback_objects.end() ) { if ( iter->cb_signal == cb_signal && iter->cb_instance == cb_instance ) iter = callback_objects.erase(iter); else ++iter; } } template::value && std::is_function::type>::value && ! std::is_function::value && std::is_pointer::value && std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr > void delCallback (FunctionPtr&& cb_func_ptr) { // Deletes entries with the given function pointer // from the callback list if ( callback_objects.empty() ) return; auto ptr = reinterpret_cast(cb_func_ptr); auto iter = callback_objects.begin(); while ( iter != callback_objects.end() ) { if ( iter->cb_function_ptr == ptr ) iter = callback_objects.erase(iter); else ++iter; } } template::value && std::is_function::type>::value && std::is_function::value && ! std::is_pointer::value && ! std::is_object::value && ! std::is_class::value , std::nullptr_t >::type = nullptr > void delCallback (Function& cb_function) { // Deletes entries with the given function from the callback list if ( callback_objects.empty() ) return; auto ptr = reinterpret_cast(&cb_function); auto iter = callback_objects.begin(); while ( iter != callback_objects.end() ) { if ( iter->cb_function_ptr == ptr ) iter = callback_objects.erase(iter); else ++iter; } } void delCallback() { // Delete all callbacks from this widget callback_objects.clear(); // function pointer } void emitCallback (const FString& emit_signal) { // Initiate callback for the given signal if ( callback_objects.empty() ) return; for (auto&& cback : callback_objects) { if ( cback.cb_signal == emit_signal ) { // Calling the stored function pointer cback.cb_function(); } } } private: // Typedefs typedef std::vector FCallbackObjects; // Data members FCallbackObjects callback_objects{}; }; } // namespace finalcut #endif // FCALLBACK_H