|
| 1 | +/* |
| 2 | + ============================================================================== |
| 3 | +
|
| 4 | + This file is part of the YUP library. |
| 5 | + Copyright (c) 2025 - [email protected] |
| 6 | +
|
| 7 | + YUP is an open source library subject to open-source licensing. |
| 8 | +
|
| 9 | + The code included in this file is provided under the terms of the ISC license |
| 10 | + http://www.isc.org/downloads/software-support-policy/isc-license. Permission |
| 11 | + to use, copy, modify, and/or distribute this software for any purpose with or |
| 12 | + without fee is hereby granted provided that the above copyright notice and |
| 13 | + this permission notice appear in all copies. |
| 14 | +
|
| 15 | + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER |
| 16 | + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE |
| 17 | + DISCLAIMED. |
| 18 | +
|
| 19 | + ============================================================================== |
| 20 | +*/ |
| 21 | + |
| 22 | +#include "yup_YupDataModel_bindings.h" |
| 23 | + |
| 24 | +#define YUP_PYTHON_INCLUDE_PYBIND11_OPERATORS |
| 25 | +#define YUP_PYTHON_INCLUDE_PYBIND11_FUNCTIONAL |
| 26 | +#include "../utilities/yup_PyBind11Includes.h" |
| 27 | + |
| 28 | +//============================================================================== |
| 29 | + |
| 30 | +namespace yup::Bindings |
| 31 | +{ |
| 32 | + |
| 33 | +namespace py = pybind11; |
| 34 | +using namespace py::literals; |
| 35 | + |
| 36 | +void registerYupDataModelBindings (py::module_& m) |
| 37 | +{ |
| 38 | + // clang-format off |
| 39 | + |
| 40 | + // ============================================================================================ yup::UndoableActionState |
| 41 | + |
| 42 | + py::enum_<UndoableActionState> (m, "UndoableActionState") |
| 43 | + .value ("Undo", UndoableActionState::Undo) |
| 44 | + .value ("Redo", UndoableActionState::Redo) |
| 45 | + .export_values(); |
| 46 | + |
| 47 | + // ============================================================================================ yup::UndoableAction |
| 48 | + |
| 49 | + py::class_<UndoableAction, PyUndoableAction, ReferenceCountedObjectPtr<UndoableAction>> classUndoableAction (m, "UndoableAction"); |
| 50 | + |
| 51 | + classUndoableAction |
| 52 | + .def (py::init<>()) |
| 53 | + .def ("isValid", &UndoableAction::isValid) |
| 54 | + .def ("perform", &UndoableAction::perform); |
| 55 | + |
| 56 | + // ============================================================================================ yup::UndoManager |
| 57 | + |
| 58 | + py::class_<UndoManager, ReferenceCountedObjectPtr<UndoManager>> classUndoManager (m, "UndoManager"); |
| 59 | + |
| 60 | + py::class_<UndoManager::ScopedTransaction> classUndoManagerScopedTransaction (classUndoManager, "ScopedTransaction"); |
| 61 | + |
| 62 | + classUndoManagerScopedTransaction |
| 63 | + .def (py::init<UndoManager&>()) |
| 64 | + .def (py::init<UndoManager&, StringRef>()); |
| 65 | + |
| 66 | + classUndoManager |
| 67 | + .def (py::init<>()) |
| 68 | + .def (py::init<int>()) |
| 69 | + .def (py::init<RelativeTime>()) |
| 70 | + .def (py::init<int, RelativeTime>()) |
| 71 | + .def ("perform", [](UndoManager& self, UndoableAction::Ptr action) { return self.perform (std::move (action)); }) |
| 72 | + .def ("beginNewTransaction", py::overload_cast<> (&UndoManager::beginNewTransaction)) |
| 73 | + .def ("beginNewTransaction", py::overload_cast<StringRef> (&UndoManager::beginNewTransaction)) |
| 74 | + .def ("getNumTransactions", &UndoManager::getNumTransactions) |
| 75 | + .def ("getTransactionName", &UndoManager::getTransactionName) |
| 76 | + .def ("getCurrentTransactionName", &UndoManager::getCurrentTransactionName) |
| 77 | + .def ("setCurrentTransactionName", &UndoManager::setCurrentTransactionName) |
| 78 | + .def ("canUndo", &UndoManager::canUndo) |
| 79 | + .def ("undo", &UndoManager::undo) |
| 80 | + .def ("canRedo", &UndoManager::canRedo) |
| 81 | + .def ("redo", &UndoManager::redo) |
| 82 | + .def ("clear", &UndoManager::clear) |
| 83 | + .def ("setEnabled", &UndoManager::setEnabled) |
| 84 | + .def ("isEnabled", &UndoManager::isEnabled); |
| 85 | + |
| 86 | + // ============================================================================================ yup::DataTreeListener |
| 87 | + |
| 88 | + py::class_<DataTreeListener, PyDataTreeListener> classDataTreeListener (m, "DataTreeListener"); |
| 89 | + |
| 90 | + classDataTreeListener |
| 91 | + .def (py::init<>()) |
| 92 | + .def ("propertyChanged", &DataTreeListener::propertyChanged) |
| 93 | + .def ("childAdded", &DataTreeListener::childAdded) |
| 94 | + .def ("childRemoved", &DataTreeListener::childRemoved) |
| 95 | + .def ("childMoved", &DataTreeListener::childMoved) |
| 96 | + .def ("treeRedirected", &DataTreeListener::treeRedirected); |
| 97 | + |
| 98 | + // ============================================================================================ yup::DataTree |
| 99 | + |
| 100 | + py::class_<DataTree> classDataTree (m, "DataTree"); |
| 101 | + |
| 102 | + py::class_<DataTree::Iterator> classDataTreeIterator (classDataTree, "Iterator"); |
| 103 | + |
| 104 | + classDataTreeIterator |
| 105 | + .def (py::init<>()) |
| 106 | + .def ("__iter__", [] (DataTree::Iterator& self) { return self; }) |
| 107 | + .def ("__next__", [] (DataTree::Iterator& self) |
| 108 | + { |
| 109 | + // We need to manually implement the iteration logic |
| 110 | + // This is a simplified version - a proper implementation would track the end |
| 111 | + auto value = *self; |
| 112 | + ++self; |
| 113 | + return value; |
| 114 | + }); |
| 115 | + |
| 116 | + py::class_<DataTree::Transaction> classDataTreeTransaction (classDataTree, "Transaction"); |
| 117 | + |
| 118 | + classDataTreeTransaction |
| 119 | + .def ("commit", &DataTree::Transaction::commit) |
| 120 | + .def ("abort", &DataTree::Transaction::abort) |
| 121 | + .def ("isActive", &DataTree::Transaction::isActive) |
| 122 | + .def ("setProperty", &DataTree::Transaction::setProperty) |
| 123 | + .def ("removeProperty", &DataTree::Transaction::removeProperty) |
| 124 | + .def ("removeAllProperties", &DataTree::Transaction::removeAllProperties) |
| 125 | + .def ("addChild", &DataTree::Transaction::addChild, "child"_a, "index"_a = -1) |
| 126 | + .def ("removeChild", py::overload_cast<const DataTree&> (&DataTree::Transaction::removeChild)) |
| 127 | + .def ("removeChild", py::overload_cast<int> (&DataTree::Transaction::removeChild)) |
| 128 | + .def ("removeAllChildren", &DataTree::Transaction::removeAllChildren) |
| 129 | + .def ("moveChild", &DataTree::Transaction::moveChild) |
| 130 | + .def ("getEffectiveChildCount", &DataTree::Transaction::getEffectiveChildCount); |
| 131 | + |
| 132 | + py::class_<DataTree::ValidatedTransaction> classDataTreeValidatedTransaction (classDataTree, "ValidatedTransaction"); |
| 133 | + |
| 134 | + classDataTreeValidatedTransaction |
| 135 | + .def ("setProperty", &DataTree::ValidatedTransaction::setProperty) |
| 136 | + .def ("removeProperty", &DataTree::ValidatedTransaction::removeProperty) |
| 137 | + .def ("addChild", &DataTree::ValidatedTransaction::addChild, "child"_a, "index"_a = -1) |
| 138 | + .def ("createAndAddChild", &DataTree::ValidatedTransaction::createAndAddChild, "childType"_a, "index"_a = -1) |
| 139 | + .def ("removeChild", &DataTree::ValidatedTransaction::removeChild) |
| 140 | + .def ("commit", &DataTree::ValidatedTransaction::commit) |
| 141 | + .def ("abort", &DataTree::ValidatedTransaction::abort) |
| 142 | + .def ("isActive", &DataTree::ValidatedTransaction::isActive) |
| 143 | + .def ("getTransaction", &DataTree::ValidatedTransaction::getTransaction, py::return_value_policy::reference); |
| 144 | + |
| 145 | + classDataTree |
| 146 | + .def (py::init<>()) |
| 147 | + .def (py::init<const Identifier&>()) |
| 148 | + .def (py::init<const Identifier&, const std::initializer_list<std::pair<Identifier, var>>&>()) |
| 149 | + .def (py::init<const Identifier&, const std::initializer_list<DataTree>&>()) |
| 150 | + .def (py::init<const Identifier&, const std::initializer_list<std::pair<Identifier, var>>&, const std::initializer_list<DataTree>&>()) |
| 151 | + .def (py::init<const DataTree&>()) |
| 152 | + .def ("isValid", &DataTree::isValid) |
| 153 | + .def ("__bool__", &DataTree::isValid) |
| 154 | + .def ("getType", &DataTree::getType) |
| 155 | + .def ("clone", &DataTree::clone) |
| 156 | + .def ("getNumProperties", &DataTree::getNumProperties) |
| 157 | + .def ("getPropertyName", &DataTree::getPropertyName) |
| 158 | + .def ("hasProperty", &DataTree::hasProperty) |
| 159 | + .def ("getProperty", &DataTree::getProperty, "name"_a, "defaultValue"_a = var()) |
| 160 | + .def ("getNumChildren", &DataTree::getNumChildren) |
| 161 | + .def ("getChild", &DataTree::getChild) |
| 162 | + .def ("getChildWithName", &DataTree::getChildWithName) |
| 163 | + .def ("indexOf", &DataTree::indexOf) |
| 164 | + .def ("getParent", &DataTree::getParent) |
| 165 | + .def ("getRoot", &DataTree::getRoot) |
| 166 | + .def ("isAChildOf", &DataTree::isAChildOf) |
| 167 | + .def ("getDepth", &DataTree::getDepth) |
| 168 | + .def ("__iter__", [] (const DataTree& self) |
| 169 | + { |
| 170 | + return py::make_iterator (self.begin(), self.end()); |
| 171 | + }, py::keep_alive<0, 1>()) |
| 172 | + .def ("forEachChild", [] (const DataTree& self, py::function callback) |
| 173 | + { |
| 174 | + self.forEachChild ([&callback] (const DataTree& child) |
| 175 | + { |
| 176 | + py::gil_scoped_acquire acquire; |
| 177 | + auto result = callback (child); |
| 178 | + if (py::isinstance<py::bool_> (result)) |
| 179 | + return result.cast<bool>(); |
| 180 | + return false; |
| 181 | + }); |
| 182 | + }) |
| 183 | + .def ("forEachDescendant", [] (const DataTree& self, py::function callback) |
| 184 | + { |
| 185 | + self.forEachDescendant ([&callback] (const DataTree& child) |
| 186 | + { |
| 187 | + py::gil_scoped_acquire acquire; |
| 188 | + auto result = callback (child); |
| 189 | + if (py::isinstance<py::bool_> (result)) |
| 190 | + return result.cast<bool>(); |
| 191 | + return false; |
| 192 | + }); |
| 193 | + }) |
| 194 | + .def ("findChildren", [] (const DataTree& self, py::function predicate) |
| 195 | + { |
| 196 | + std::vector<DataTree> results; |
| 197 | + self.findChildren (results, [&predicate] (const DataTree& child) |
| 198 | + { |
| 199 | + py::gil_scoped_acquire acquire; |
| 200 | + return predicate (child).cast<bool>(); |
| 201 | + }); |
| 202 | + return results; |
| 203 | + }) |
| 204 | + .def ("findChild", [] (const DataTree& self, py::function predicate) |
| 205 | + { |
| 206 | + return self.findChild ([&predicate] (const DataTree& child) |
| 207 | + { |
| 208 | + py::gil_scoped_acquire acquire; |
| 209 | + return predicate (child).cast<bool>(); |
| 210 | + }); |
| 211 | + }) |
| 212 | + .def ("findDescendants", [] (const DataTree& self, py::function predicate) |
| 213 | + { |
| 214 | + std::vector<DataTree> results; |
| 215 | + self.findDescendants (results, [&predicate] (const DataTree& child) |
| 216 | + { |
| 217 | + py::gil_scoped_acquire acquire; |
| 218 | + return predicate (child).cast<bool>(); |
| 219 | + }); |
| 220 | + return results; |
| 221 | + }) |
| 222 | + .def ("findDescendant", [] (const DataTree& self, py::function predicate) |
| 223 | + { |
| 224 | + return self.findDescendant ([&predicate] (const DataTree& child) |
| 225 | + { |
| 226 | + py::gil_scoped_acquire acquire; |
| 227 | + return predicate (child).cast<bool>(); |
| 228 | + }); |
| 229 | + }) |
| 230 | + .def ("createXml", &DataTree::createXml) |
| 231 | + .def_static ("fromXml", py::overload_cast<const XmlElement&> (&DataTree::fromXml)) |
| 232 | + .def ("writeToBinaryStream", &DataTree::writeToBinaryStream) |
| 233 | + .def_static ("readFromBinaryStream", &DataTree::readFromBinaryStream) |
| 234 | + .def ("createJson", &DataTree::createJson) |
| 235 | + .def_static ("fromJson", &DataTree::fromJson) |
| 236 | + .def ("addListener", &DataTree::addListener, py::keep_alive<1, 2>()) |
| 237 | + .def ("removeListener", &DataTree::removeListener) |
| 238 | + .def ("removeAllListeners", &DataTree::removeAllListeners) |
| 239 | + .def (py::self == py::self) |
| 240 | + .def (py::self != py::self) |
| 241 | + .def ("isEquivalentTo", &DataTree::isEquivalentTo) |
| 242 | + .def ("beginTransaction", py::overload_cast<UndoManager*> (&DataTree::beginTransaction), "undoManager"_a = nullptr) |
| 243 | + .def ("__repr__", [] (const DataTree& self) |
| 244 | + { |
| 245 | + String result; |
| 246 | + result |
| 247 | + << "<" << Helpers::pythonizeModuleClassName (PythonModuleName, typeid (DataTree).name(), 1) |
| 248 | + << " object at " << String::formatted ("%p", std::addressof (self)) |
| 249 | + << " type=\"" << self.getType().toString() << "\">"; |
| 250 | + return result; |
| 251 | + }); |
| 252 | + |
| 253 | + // clang-format on |
| 254 | +} |
| 255 | + |
| 256 | +} // namespace yup::Bindings |
0 commit comments