File indexing completed on 2024-05-12 15:56:59

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_SIGNAL_COMPRESSOR_WITH_PARAM_H
0008 #define __KIS_SIGNAL_COMPRESSOR_WITH_PARAM_H
0009 
0010 #include <kis_signal_compressor.h>
0011 #include <functional>
0012 
0013 
0014 /**
0015  * A special class that converts a Qt signal into a std::function call.
0016  *
0017  * Usage:
0018  *
0019  *        \code{.cpp}
0020  *
0021  *        std::function<void ()> destinationFunctionCall(std::bind(someNiceFunc, firstParam, secondParam));
0022  *        SignalToFunctionProxy proxy(destinationFunctionCall);
0023  *        connect(srcObject, SIGNAL(sigSomethingChanged()), &proxy, SLOT(start()));
0024  *
0025  *        \endcode
0026  *
0027  * Now every time sigSomethingChanged() is emitted, someNiceFunc is
0028  * called. std::bind allows us to call any method of any class without
0029  * changing signature of the class or creating special wrappers.
0030  */
0031 class KRITAGLOBAL_EXPORT SignalToFunctionProxy : public QObject
0032 {
0033     Q_OBJECT
0034 public:
0035     using TrivialFunction = std::function<void ()>;
0036 
0037 public:
0038     SignalToFunctionProxy(TrivialFunction function)
0039         : m_function(function)
0040     {
0041     }
0042 
0043 public Q_SLOTS:
0044     void start() {
0045         m_function();
0046     }
0047 
0048 private:
0049     TrivialFunction m_function;
0050 };
0051 
0052 /**
0053  * A special class that converts a standard function call into Qt signal
0054  *
0055  * Usage:
0056  *
0057  *        \code{.cpp}
0058  *
0059  *        FunctionToSignalProxy proxy;
0060  *        connect(&proxy, SIGNAL(timeout()), &dstObject, SLOT(someDestinationSlot()));
0061  *
0062  *        \endcode
0063  *
0064  *        Now every time `proxy.start()` is called, the signal `timeout()` is
0065  *        forwarded to `someDestinationSlot()`
0066  */
0067 class KRITAGLOBAL_EXPORT FunctionToSignalProxy : public QObject
0068 {
0069     Q_OBJECT
0070 
0071 public:
0072     void start() {
0073         emit timeout();
0074     }
0075 
0076 Q_SIGNALS:
0077     void timeout();
0078 };
0079 
0080 
0081 
0082 /**
0083  * A special class for deferring and comressing events with one
0084  * parameter of type T. This works like KisSignalCompressor but can
0085  * handle events with one parameter. Due to limitation of the Qt this
0086  * doesn't allow signal/slots, so it uses std::function instead.
0087  *
0088  * In the end (after a timeout) the latest param value is returned to
0089  * the callback.
0090  *
0091  *        Usage:
0092  *
0093  *        \code{.cpp}
0094  *
0095  *        using namespace std::placeholders; // For _1 placeholder
0096  *
0097  *        // prepare the callback function
0098  *        std::function<void (qreal)> callback(
0099  *            std::bind(&LutDockerDock::setCurrentExposureImpl, this, _1));
0100  *
0101  *        // Create the compressor object
0102  *        KisSignalCompressorWithParam<qreal> compressor(40, callback);
0103  *
0104  *        // When event comes:
0105  *        compressor.start(0.123456);
0106  *
0107  *        \endcode
0108  */
0109 
0110 template <typename T>
0111 class KisSignalCompressorWithParam
0112 {
0113 public:
0114     using CallbackFunction = std::function<void (T)>;
0115 
0116 public:
0117 KisSignalCompressorWithParam(int delay, CallbackFunction function, KisSignalCompressor::Mode mode = KisSignalCompressor::FIRST_ACTIVE)
0118         : m_compressor(delay, mode),
0119           m_function(function)
0120     {
0121         std::function<void ()> callback(
0122             std::bind(&KisSignalCompressorWithParam<T>::fakeSlotTimeout, this));
0123         m_signalProxy.reset(new SignalToFunctionProxy(callback));
0124 
0125         m_compressor.connect(&m_compressor, SIGNAL(timeout()), m_signalProxy.data(), SLOT(start()));
0126     }
0127 
0128     ~KisSignalCompressorWithParam()
0129     {
0130     }
0131 
0132     void start(T param) {
0133         m_currentParamValue = param;
0134         m_compressor.start();
0135     }
0136 
0137     void stop() {
0138         m_compressor.stop();
0139     }
0140 
0141     bool isActive() const {
0142         return m_compressor.isActive();
0143     }
0144 
0145     void setDelay(int value) {
0146         m_compressor.setDelay(value);
0147     }
0148 
0149 private:
0150     void fakeSlotTimeout() {
0151         m_function(m_currentParamValue);
0152     }
0153 
0154 private:
0155     KisSignalCompressor m_compressor;
0156     CallbackFunction m_function;
0157     QScopedPointer<SignalToFunctionProxy> m_signalProxy;
0158     T m_currentParamValue;
0159 };
0160 
0161 #endif /* __KIS_SIGNAL_COMPRESSOR_WITH_PARAM_H */