aboutsummaryrefslogtreecommitdiff
path: root/libs/plugin_python/src/pybind11-qt/include/pybind11_qt/pybind11_qt.h
blob: e803e9f7c02b2c65624fb3be55a00a2e7e7ca278 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#ifndef PYTHON_PYBIND11_QT_HPP
#define PYTHON_PYBIND11_QT_HPP

// this header defines many type casters for Qt types, including:
// - basic Qt types such as QString and QVariant - those do not have PyQt6 equivalent
// - QFlags<> class templates
// - containers such as QList<>, QSet<>, etc., the QList<> casters is more flexible than
//   the std::vector<> or std::list<> ones as it accepts any iterable
// - many Qt enumeration types (see pybind11_qt_enums)
// - many Qt classes with PyQt6 equivalent
//   - copyable type are copied between Python and C++
//   - non-copyable type (QObject, QWidget, QMainWindow) are always owned by the C++
//     side, even when constructed on the Python side, and owned their corresponding
//     Python object, e.g., an instance of a class inheriting QWidget created on the
//     Python side can be safely used in C++ since the Python object will be owned by
//     the C++ QWidget object
//

#include "pybind11_qt_basic.h"
#include "pybind11_qt_containers.h"
#include "pybind11_qt_enums.h"
#include "pybind11_qt_holder.h"
#include "pybind11_qt_objects.h"
#include "pybind11_qt_qflags.h"

namespace pybind11::qt {

    /**
     * @brief Tie the lifetime of the Python object to the lifetime of the given
     * QObject.
     *
     * @param owner QObject that will own the python object.
     * @param child Python object that the QObject will own.
     */
    inline void set_qt_owner(QObject* owner, object child)
    {
        new detail::qt::qobject_holder_impl{owner, child};
    }

    /**
     * @brief Tie the lifetime of the given object to the lifetime of the corresponding
     * Python object.
     *
     * This object must have been created from Python and must inherit QObject.
     *
     * @param object Object to tie.
     */
    template <typename Class>
    void set_qt_owner(Class* object)
    {
        static_assert(std::is_base_of_v<QObject, Class>);
        new detail::qt::qobject_holder_impl{object};
    }

    /**
     * @brief Add Qt "delegate" to the given class.
     *
     * This function defines two methods: __getattr__ and name, where name will
     * simply return the PyQtX object as a QClass* object, while __getattr__
     * will delegate to the underlying QClass object when required.
     *
     * This allow access to Qt interface for object exposed using pybind11
     * (e.g., signals, methods from QObject or QWidget, etc.).
     *
     * @param pyclass Python class to define the methods on.
     * @param name Name of the method to retrieve the underlying object.
     *
     * @tparam QClass Name of the Qt class, cannot be deduced.
     * @tparam Class Class being wrapped, deduced.
     * @tparam Args... Arguments of the class template parameters, deduced.
     */
    template <class QClass, class Class, class... Args>
    auto& add_qt_delegate(pybind11::class_<Class, Args...>& pyclass, const char* name)
    {
        return pyclass
            .def(name,
                 [](Class* w) -> QClass* {
                     return w;
                 })
            .def(
                "__getattr__", +[](Class* w, pybind11::str str) -> pybind11::object {
                    return pybind11::cast((QClass*)w).attr(str);
                });
    }

}  // namespace pybind11::qt

#endif