File indexing completed on 2024-12-22 05:11:50

0001 /*
0002     SPDX-FileCopyrightText: 2019 Ivan Čukić <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef VOY_WRAPPERS_QT_CONNECT_H
0008 #define VOY_WRAPPERS_QT_CONNECT_H
0009 
0010 // STL
0011 #include <functional>
0012 
0013 // Qt
0014 #include <QObject>
0015 #include <QMetaObject>
0016 #include <QDebug>
0017 
0018 // Self
0019 #include "../../utils.h"
0020 #include "../../traits.h"
0021 #include "../../dsl/node_tags.h"
0022 
0023 namespace voy::qt {
0024 
0025 using voy::utils::non_copyable;
0026 
0027 using voy::dsl::continuator_base,
0028       voy::dsl::source_node_tag;
0029 
0030 namespace detail {
0031 
0032     template <typename T, typename Object, typename Signal>
0033     class signal_impl: non_copyable {
0034         voy_assert_value_type(T);
0035 
0036     public:
0037         using node_category = source_node_tag;
0038 
0039         explicit signal_impl(Object* sender, Signal signal)
0040             : m_sender{sender}
0041             , m_signal{std::move(signal)}
0042         {
0043         }
0044 
0045         template <typename Cont>
0046         class node: public continuator_base<Cont>, non_copyable {
0047             using base = continuator_base<Cont>;
0048 
0049         public:
0050             node(Object* sender, Signal signal, Cont cont)
0051                 : base{std::move(cont)}
0052                 , m_sender{sender}
0053                 , m_signal{std::move(signal)}
0054             {
0055             }
0056 
0057             void init()
0058             {
0059                 qDebug() << "Calling init";
0060                 base::init();
0061 
0062                 if constexpr (std::is_same_v<void, T>) {
0063                     m_connection = QObject::connect(
0064                             m_sender, m_signal,
0065                             [this] (auto value) {
0066                                 // TODO: This needs to be async
0067                                 base::emit(std::move(value));
0068                             });
0069                 } else {
0070                     m_connection = QObject::connect(
0071                             m_sender, m_signal,
0072                             [this] (T value) {
0073                                 // TODO: This needs to be async
0074                                 base::emit(std::move(value));
0075                             });
0076                 }
0077 
0078                 QObject::connect(
0079                         m_sender, &QObject::destroyed,
0080                         [this] {
0081                             base::notify_ended();
0082                         });
0083             }
0084 
0085         private:
0086             QMetaObject::Connection m_connection;
0087             Object* m_sender;
0088             Signal m_signal;
0089         };
0090 
0091 
0092         template <typename Cont>
0093         auto with_continuation(Cont&& cont) &&
0094         {
0095             return node<Cont>(m_sender, std::move(m_signal), voy_fwd(cont));
0096         }
0097 
0098     private:
0099         Object* m_sender;
0100         Signal m_signal;
0101 
0102     };
0103 
0104 
0105 
0106     template <typename Object, typename Slot>
0107     class slot_impl: non_copyable {
0108     public:
0109         using node_category = sink_node_tag;
0110 
0111         explicit slot_impl(Object* object, Slot slot)
0112             : m_receiver(object)
0113             , m_slot(slot)
0114         {
0115         }
0116 
0117         template <typename T>
0118         void operator() (T&& value) const
0119         {
0120             std::invoke(m_slot, m_receiver, voy_fwd(value));
0121         }
0122 
0123         void init()
0124         {
0125         }
0126 
0127         void notify_ended() const
0128         {
0129         }
0130 
0131     private:
0132         Object* m_receiver;
0133         Slot m_slot;
0134     };
0135 
0136 
0137 } // namespace detail
0138 
0139 
0140 template <typename T = void, typename Object = QObject, typename Signal = void>
0141 auto signal(Object* sender, Signal&& signal)
0142 {
0143     return detail::signal_impl<T, Object, Signal>(sender, voy_fwd(signal));
0144 }
0145 
0146 
0147 template <typename Object, typename Slot>
0148 auto slot(Object* receiver, Slot&& slot)
0149 {
0150     return detail::slot_impl<Object, Slot>(receiver, voy_fwd(slot));
0151 }
0152 
0153 } // namespace voy
0154 
0155 #endif // include guard
0156