Closed AaronFrans closed 4 months ago
member::get, function::call and other dynamic methods return "uvalue", which is essentially "std::any". To do anything with this value in the "static world", you must either have a static type, or something like switching by type or map (type -> function with the desired functionality). Here you can find a little example how to work with uvalues: https://github.com/BlackMATov/meta.hpp/blob/main/develop/manuals/meta_examples/uvalue_example.cpp
So there's no way to get the value without castiung it with the as function. Would you recommend usining getter and setter functions instead then? I'm trying to get to something like the component in unity, where i can gget all of my gameobjects andedit their components in 1 ui element.
To make an analog of a Unity-like inspector, you could write something like property drawers for each type you want to show (which is what Unity does under the hood). Little pseudocode of this:
class member_drawer {
public:
virtual void draw(const meta::uvalue& instance, const meta::member& member) = 0;
};
class int_member_drawer : public member_drawer {
public:
void draw(const meta::uvalue& instance, const meta::member& member) override
{
meta::uvalue value = member.get(instance);
int typed_value = value.as<int>();
if ( ImGui::InputInt(member.get_name().c_str(), &typed_value) ) {
member.set(instance, typed_value);
}
}
};
class float_member_drawer : public member_drawer {
public:
void draw(const meta::uvalue& instance, const meta::member& member) override
{
meta::uvalue value = member.get(instance);
float typed_value = value.as<float>();
if ( ImGui::InputFloat(member.get_name().c_str(), &typed_value) ) {
member.set(instance, typed_value);
}
}
};
using member_drawer_ptr = std::shared_ptr<member_drawer>;
using member_drawer_map = std::map<meta::any_type, member_drawer_ptr>;
member_drawer_map member_drawers = {
{ meta::resolve_type<int>(), std::make_shared<int_member_drawer>() },
{ meta::resolve_type<float>(), std::make_shared<float_member_drawer>() }
};
And using:
struct component {
component() = default;
component(const component&) = default;
virtual ~component() = default;
META_HPP_ENABLE_POLY_INFO()
};
struct position_component : component {
META_HPP_ENABLE_POLY_INFO(component)
public:
explicit position_component(int nx, int ny) : x{nx}, y{ny} {}
int x{};
int y{};
};
struct rotation_component : component {
META_HPP_ENABLE_POLY_INFO(component)
public:
explicit rotation_component(float nr) : r{nr} {}
float r{};
};
void draw_component_inspector(component* component) {
// meta_poly_ptr returns a pointer of the most derived type
// (position_component* or rotation_component* in this case)
meta::uvalue instance_ptr = component->meta_poly_ptr();
meta::pointer_type instance_ptr_type = derived_instance_ptr.get_type().as_pointer();
// to get all members of the component we should extract a class type from the pointer
meta::class_type instance_type = derived_instance_ptr_type.get_data_type().as_class();
for (const meta::member& member : instance_type.get_members()) {
member_drawers.at(member.get_type())->draw(instance_ptr, member);
}
}
And of course after this simple inspector you can add custom drawers support, additional metadata to draw sliders, ranges and so on.
Enjoy! :-)
I see, I'll test this on but this seems like it will solve my issues. Thank You!
Can I close the issue? :-)
Sorry forgot, its working :)
Is there a way to get the value from a member without knowing the type? I'm currently iterating through a list of members via the get_memberts() function. I've tried a few different things, but can't seem to make it work.
This is the code: