1 #ifndef LXGUI_UTILS_SIGNAL_HPP
2 #define LXGUI_UTILS_SIGNAL_HPP
4 #include "lxgui/utils.hpp"
5 #include "lxgui/utils_observer.hpp"
6 #include "lxgui/utils_view.hpp"
17 namespace signal_impl {
20 bool disconnected =
false;
32 explicit connection(utils::observer_ptr<signal_impl::slot_base> slot) noexcept :
33 slot_(std::move(slot)) {}
47 if (
auto* raw = slot_.get()) {
48 raw->disconnected =
true;
55 if (
auto* raw = slot_.get())
56 return !raw->disconnected;
62 utils::observer_ptr<signal_impl::slot_base> slot_;
159 struct slot : signal_impl::slot_base {
160 explicit slot(
function_type func) noexcept : callback(std::move(func)) {}
188 using container_type = std::vector<U>;
197 using slot_list = container_type<utils::owner_ptr<slot>>;
200 template<
typename BaseIterator>
201 struct slot_dereferencer {
203 static data_type dereference(
const BaseIterator& iter) noexcept {
204 return (*iter)->callback;
209 template<
typename BaseIterator>
210 struct non_disconnected_filter {
211 static bool is_included(
const BaseIterator& iter) noexcept {
212 return !(*iter)->disconnected;
222 signal() : impl_(std::make_shared<implementation>()) {}
239 if (impl_->recursion == 0u) {
240 impl_->slots.clear();
250 for (
auto& slt : impl_->slots)
251 slt->disconnected =
true;
258 [[nodiscard]]
bool empty() const noexcept {
259 const auto&
slots = impl_->slots;
284 impl_->slots.push_back(utils::make_owned<slot>(std::move(
function)));
292 template<
typename... Args>
298 [[maybe_unused]]
const auto impl_copy_ptr = impl_;
300 const auto&
slots = impl.slots;
301 auto& recursion = impl.recursion;
308 const std::size_t num_slots =
slots.size();
309 for (std::size_t i = 0; i < num_slots; ++i) {
310 auto& slt = *
slots[i];
311 if (!slt.disconnected)
312 slt.callback(args...);
318 impl.garbage_collect();
322 struct implementation {
324 std::size_t recursion = 0u;
326 void garbage_collect() noexcept {
327 auto iter = std::remove_if(
334 std::shared_ptr<implementation> impl_;
Object representing the connection between a slot and a signal.
connection()=default
Default constructor, no connection.
bool connected() const noexcept
Check if this slot is still connected.
connection(connection &&)=default
connection(const connection &)=default
connection & operator=(const connection &)=default
void disconnect() noexcept
Disconnect the slot.
connection & operator=(connection &&)=default
A connection that automatically disconnects when going out of scope.
scoped_connection & operator=(const scoped_connection &)=delete
scoped_connection(scoped_connection &&)=default
~scoped_connection() noexcept
Destructor, disconnects.
scoped_connection(connection c) noexcept
Conversion constructor from a raw connection.
scoped_connection(const scoped_connection &)=delete
void disconnect() noexcept
Disconnect the slot.
scoped_connection & operator=(scoped_connection &&)=default
scoped_connection()=default
Default constructor, no connection.
Generic class for observing and triggering events.
slot_list_view slots() const noexcept
Return a constant view onto the connected slots.
utils::view::adaptor< slot_list, slot_dereferencer, non_disconnected_filter > slot_list_view
Type of the view returned by slots().
signal & operator=(signal &&)=default
void disconnect_all() noexcept
Disconnects all slots.
bool empty() const noexcept
Check if this signal contains any slot.
signal & operator=(const signal &)=delete
connection connect(function_type function)
Connect a new slot to this signal.
signal(const signal &)=delete
signal()
Default constructor (no slot).
signal(signal &&)=default
void operator()(Args &&... args)
Trigger the signal.
std::function< T > function_type
Type of the callable function stored in a slot. Can use any function/delegate type here,...
Allow iterating over a container without access to the container itself.