Skip to content

Commit 7ac33da

Browse files
committed
Added data model python bindings
1 parent 8aeed3a commit 7ac33da

File tree

8 files changed

+1210
-4
lines changed

8 files changed

+1210
-4
lines changed
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
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
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
#pragma once
23+
24+
#if ! YUP_MODULE_AVAILABLE_yup_data_model
25+
#error This binding file requires adding the yup_data_model module in the project
26+
#else
27+
#include <yup_data_model/yup_data_model.h>
28+
#endif
29+
30+
#include "yup_YupEvents_bindings.h"
31+
32+
#include "../utilities/yup_PyBind11Includes.h"
33+
34+
namespace yup::Bindings
35+
{
36+
37+
//==============================================================================
38+
39+
void registerYupDataModelBindings (pybind11::module_& m);
40+
41+
//==============================================================================
42+
43+
struct PyDataTreeListener : public yup::DataTreeListener
44+
{
45+
void propertyChanged (yup::DataTree& tree, const yup::Identifier& property) override
46+
{
47+
PYBIND11_OVERRIDE (void, yup::DataTreeListener, propertyChanged, tree, property);
48+
}
49+
50+
void childAdded (yup::DataTree& parent, yup::DataTree& child) override
51+
{
52+
PYBIND11_OVERRIDE (void, yup::DataTreeListener, childAdded, parent, child);
53+
}
54+
55+
void childRemoved (yup::DataTree& parent, yup::DataTree& child, int formerIndex) override
56+
{
57+
PYBIND11_OVERRIDE (void, yup::DataTreeListener, childRemoved, parent, child, formerIndex);
58+
}
59+
60+
void childMoved (yup::DataTree& parent, yup::DataTree& child, int oldIndex, int newIndex) override
61+
{
62+
PYBIND11_OVERRIDE (void, yup::DataTreeListener, childMoved, parent, child, oldIndex, newIndex);
63+
}
64+
65+
void treeRedirected (yup::DataTree& tree) override
66+
{
67+
PYBIND11_OVERRIDE (void, yup::DataTreeListener, treeRedirected, tree);
68+
}
69+
};
70+
71+
//==============================================================================
72+
73+
struct PyUndoableAction : public yup::UndoableAction
74+
{
75+
bool isValid() const override
76+
{
77+
PYBIND11_OVERRIDE_PURE (bool, yup::UndoableAction, isValid);
78+
}
79+
80+
bool perform (yup::UndoableActionState stateToPerform) override
81+
{
82+
PYBIND11_OVERRIDE_PURE (bool, yup::UndoableAction, perform, stateToPerform);
83+
}
84+
};
85+
86+
} // namespace yup::Bindings

modules/yup_python/modules/yup_YupMain_module.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,9 @@
2828
#include "../bindings/yup_YupEvents_bindings.h"
2929
#endif
3030

31-
/*
3231
#if YUP_MODULE_AVAILABLE_yup_data_model
3332
#include "../bindings/yup_YupDataModel_bindings.h"
3433
#endif
35-
*/
3634

3735
#if YUP_MODULE_AVAILABLE_yup_graphics
3836
#include "../bindings/yup_YupGraphics_bindings.h"
@@ -82,11 +80,9 @@ PYBIND11_MODULE (YUP_PYTHON_MODULE_NAME, m)
8280
yup::Bindings::registerYupEventsBindings (m);
8381
#endif
8482

85-
/*
8683
#if YUP_MODULE_AVAILABLE_yup_data_model
8784
yup::Bindings::registerYupDataModelBindings (m);
8885
#endif
89-
*/
9086

9187
#if YUP_MODULE_AVAILABLE_yup_graphics
9288
yup::Bindings::registerYupGraphicsBindings (m);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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 "bindings/yup_YupDataModel_bindings.cpp"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Test module for yup_data_model bindings

0 commit comments

Comments
 (0)