Topic: RFC1 - Signals
As it is, only delegates of the form void(void) can be attached to an sfg::Signal object. In C++03 without std::function or std::bind support we had to roll our own delegate structure to avoid having to depend on boost. To keep it simple and relatively fast, we decided that instead of being a message with internal state, an sfg::Signal should just be an interface that invokes whatever functions were attached to it. The invocation of those functions was the information that a widget would want to convey back to the end user. Conceptually, a widget should not have to pass back newly created information during the invocation of the attached functions because its state should be easy to query and any information that did not originate from the widget itself should not have to be forwarded by the widget since this information should be available for the user to query as well.
Due to the asynchronous nature of event queuing, the event and input state that triggered the sfg::Signal must be bound to the invocation itself since past states cannot be queried easily by the user. This means that a limited form of message passing is required to ease the use of the interface without any non-trivial workarounds.
Change the signature of sfg::Signal functions to pass the triggering event, if available.
With the outstanding refactor into C++11, we will probably replace Don Clugston's Fast Delegate implementation with std::function, to enable more flexible usage of the interface and allow the user to use std::bind as well.
When considering a typical scenario where std::bind might be used, one has to take into account that the user might be migrating from another UI library and has become accustomed to the way they handle their events. A very common practice is to provide the invoking widget as part of the message passed to the user code in order to enable easy decoupled access to its state when handling the signal. Because std::bind support will be implicitly available when sfg::Signals make use of std::function, I predict users will start connecting sfg::Signals in the following way:
widget->GetSignal( sfg::Widget::OnLeftClick ).Connect( std::bind( &SomeStruct::SomeFunc, &some_struct, std::placeholders::_1, widget ) );
This would make available the widget when the user's function is called, however, because widget is a shared_ptr, storing it inside the std::bind expression, which is indirectly owned by the widget itself, would create an ownership cycle leading to the widget never being destroyed and leaks occurring. To solve this, the user would need to bind a weak_ptr instead of a shared_ptr, however this would mean they would need to acquire ownership of the widget inside their function every time it is called. This is first of all, very annoying for the user and might lead to unnecessary overhead, and assuming many users might not have much experience with shared_ptr ownership concepts, this might become the source of hard to debug leaks.
Incorporating the previous change, the signature of the functions attached to sfg::Signal would become:
void func( const sfg::Widget::Ptr& widget, const sf::Event& event )
sf::Event might be replaced by an arbitrary event structure in the future.
Please comment on this idea.