add vtk Properties

This commit is contained in:
AndreaRigoni
2026-03-23 15:09:35 +00:00
parent 94843de711
commit 5d0efb3078
9 changed files with 263 additions and 17 deletions

View File

@@ -64,6 +64,7 @@ public:
Vector<Signal> sigv;
Vector<Slot> slov;
std::vector<PropertyBase*> m_Properties;
std::vector<PropertyBase*> m_DynamicProperties;
};
// Implementations of Property methods
@@ -71,6 +72,13 @@ void Object::RegisterProperty(PropertyBase* prop) {
if (prop) d->m_Properties.push_back(prop);
}
void Object::RegisterDynamicProperty(PropertyBase* prop) {
if (prop) {
d->m_DynamicProperties.push_back(prop);
d->m_Properties.push_back(prop);
}
}
const std::vector<PropertyBase*>& Object::GetProperties() const {
return d->m_Properties;
}
@@ -109,7 +117,12 @@ Object::Object() : d(new ObjectPrivate) {}
Object::Object(const Object &copy) : d(new ObjectPrivate(*copy.d)) {}
Object::~Object() { delete d; }
Object::~Object() {
for (auto* p : d->m_DynamicProperties) {
delete p;
}
delete d;
}
void Object::DeepCopy(const Object &copy) {
// should lock to be tread safe //

View File

@@ -85,6 +85,7 @@ public:
////////////////////////////////////////////////////////////////////////////
// PROPERTIES //
void RegisterProperty(PropertyBase* prop);
void RegisterDynamicProperty(PropertyBase* prop);
const std::vector<PropertyBase*>& GetProperties() const;
////////////////////////////////////////////////////////////////////////////

View File

@@ -42,38 +42,50 @@ public:
template <typename T>
class Property : public PropertyBase {
public:
Property(Object* owner, const std::string& name, const T& defaultValue = T())
: m_owner(owner), m_name(name), m_value(defaultValue) {
// PROXY: Use an existing variable as back-end storage
Property(Object* owner, const std::string& name, T* valuePtr)
: m_owner(owner), m_name(name), m_value(valuePtr), m_own(false) {
if (m_owner) {
m_owner->RegisterProperty(this);
}
}
virtual ~Property() {}
// MANAGED: Create and own internal storage
Property(Object* owner, const std::string& name, const T& defaultValue = T())
: m_owner(owner), m_name(name), m_value(new T(defaultValue)), m_own(true) {
if (m_owner) {
m_owner->RegisterProperty(this);
}
}
virtual ~Property() {
if (m_own) delete m_value;
}
const std::string& GetName() const override { return m_name; }
const char* GetTypeName() const override { return typeid(T).name(); }
std::string GetValueAsString() const override {
try {
return boost::lexical_cast<std::string>(m_value);
return boost::lexical_cast<std::string>(*m_value);
} catch (const boost::bad_lexical_cast&) {
std::stringstream ss;
ss << m_value;
ss << *m_value;
return ss.str();
}
}
// Accessors
const T& Get() const { return m_value; }
const T& Get() const { return *m_value; }
void Set(const T& value) {
if (m_value != value) {
m_value = value;
if (*m_value != value) {
*m_value = value;
ULIB_SIGNAL_EMIT(Property<T>::PropertyChanged);
}
}
// Operators for seamless usage
operator const T&() const { return m_value; }
operator const T&() const { return *m_value; }
Property& operator=(const T& value) {
Set(value);
return *this;
@@ -86,7 +98,7 @@ public:
// Serialization
template <class ArchiveT>
void serialize_impl(ArchiveT & ar, const unsigned int version) {
ar & boost::serialization::make_nvp(m_name.c_str(), m_value);
ar & boost::serialization::make_nvp(m_name.c_str(), *m_value);
}
void serialize(Archive::xml_oarchive & ar, const unsigned int v) override { serialize_impl(ar, v); }
@@ -99,7 +111,8 @@ public:
private:
std::string m_name;
T m_value;
T* m_value;
bool m_own;
Object* m_owner;
};
@@ -118,11 +131,91 @@ typedef Property<Bool_t> BoolProperty;
/**
* @brief Macro to simplify property declaration within a class.
* Usage: ULIB_PROPERTY(float, Width, 1.0f)
* It creates a raw member m_Width and a Property proxy Width.
*/
#define ULIB_PROPERTY(type, name, defaultValue) \
Property<type> name = Property<type>(this, #name, defaultValue);
type m_##name = defaultValue; \
Property<type> name = Property<type>(this, #name, &m_##name);
} // namespace uLib
namespace uLib {
namespace Archive {
class property_register_archive;
} // namespace Archive
} // namespace uLib
namespace boost {
namespace archive {
namespace detail {
template <>
class interface_oarchive<uLib::Archive::property_register_archive>
: public uLib_interface_oarchive<uLib::Archive::property_register_archive> {};
} // namespace detail
} // namespace archive
} // namespace boost
namespace uLib {
namespace Archive {
/**
* @brief A special archive that creates and registers Property proxies
* for any member it encounters wrapped in HRP().
*/
class property_register_archive :
public boost::archive::detail::common_oarchive<property_register_archive>
{
Object* m_Object;
public:
friend class boost::archive::detail::interface_oarchive<property_register_archive>;
friend class boost::archive::save_access;
typedef boost::archive::detail::common_oarchive<property_register_archive> detail_common_oarchive;
property_register_archive(Object* obj) :
boost::archive::detail::common_oarchive<property_register_archive>(boost::archive::no_header),
m_Object(obj) {}
// Core logic: encounter HRP -> Create Dynamic Property
template<class T>
void save_override(const boost::serialization::hrp<T> &t) {
if (m_Object) {
// We use const_cast because we are just creating a proxy to the member
m_Object->RegisterDynamicProperty(
new Property<T>(m_Object, t.name(), &const_cast<boost::serialization::hrp<T>&>(t).value())
);
}
}
// Handle standard NVPs by recursing (important for base classes)
template<class T>
void save_override(const boost::serialization::nvp<T> &t) {
this->detail_common_oarchive::save_override(t.const_value());
}
// Ignore everything else
template<class T> void save_override(const T &t) {}
// Required attribute overrides for common_oarchive
void save_override(const boost::archive::object_id_type & t) {}
void save_override(const boost::archive::object_reference_type & t) {}
void save_override(const boost::archive::version_type & t) {}
void save_override(const boost::archive::class_id_type & t) {}
void save_override(const boost::archive::class_id_optional_type & t) {}
void save_override(const boost::archive::class_id_reference_type & t) {}
void save_override(const boost::archive::class_name_type & t) {}
void save_override(const boost::archive::tracking_type & t) {}
};
/**
* @brief Convenience macro to automatically activate and register all HRP members
* as uLib properties. Usage: ULIB_ACTIVATE_PROPERTIES(obj)
*/
#define ULIB_ACTIVATE_PROPERTIES(obj) \
{ uLib::Archive::property_register_archive _ar_tmp(&(obj)); (obj).serialize(_ar_tmp, 0); }
} // namespace Archive
} // namespace uLib
#endif // U_CORE_PROPERTY_H

View File

@@ -1,5 +1,7 @@
#include <iostream>
#include <sstream>
#include "Core/Object.h"
#include "Core/Property.h"
#include "Core/Serializable.h"
#include "Core/Archives.h"
@@ -8,13 +10,29 @@ using namespace uLib;
struct SimpleObject {
int value;
std::string name;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & HRP(value);
ar & HRP(name);
}
};
struct DynamicObject : public Object {
float width;
int height;
DynamicObject() : width(10.0f), height(20) {
// Automatic registration of properties based on serialize/HRP
ULIB_ACTIVATE_PROPERTIES(*this);
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & HRP(width);
ar & HRP(height);
}
};
int main() {
SimpleObject obj;
@@ -45,5 +63,21 @@ int main() {
}
std::cout << ss.str() << std::endl;
std::cout << "Testing Dynamic Property Creation via ULIB_ACTIVATE_PROPERTIES macro..." << std::endl;
DynamicObject dynObj;
// (properties were already created in DynamicObject constructor via macro)
std::cout << "Registered Properties in dynObj:" << std::endl;
const auto& props = dynObj.GetProperties();
for (auto* p : props) {
std::cout << " - [" << p->GetTypeName() << "] " << p->GetName() << " = " << p->GetValueAsString() << std::endl;
}
if (props.size() == 2) {
std::cout << "Dynamic Property Creation SUCCESS!" << std::endl;
} else {
std::cout << "Dynamic Property Creation FAILED (Expected 2, got " << props.size() << ")" << std::endl;
}
return 0;
}