--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/linetypes/propertygenerics.h Mon May 11 12:18:59 2020 +0300 @@ -0,0 +1,153 @@ +#pragma once +#include "main.h" +#include "colors.h" + +class Vec3Editor; +class MatrixEditor; + +namespace ldraw +{ + enum class Property; + struct PropertyKeyValue; + template<Property property> + struct PropertyTraits + { + static constexpr bool defined = false; + }; +} + +/** + * Different properties + */ +enum class ldraw::Property +{ + Color, // Color of the object + Text, // Text contained in a comment + Point0, // First vertex in a polygon or edge line + Point1, // Second vertex in a polygon or edge line + Point2, // Third vertex in a polygon + Point3, // Fourth vertex in a quadrilateral + Transformation, // 4x4 transformation matrix of a subfile reference + ReferenceName, // Subfile reference name + IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT + ErrorMessage // For error lines, why parsing failed +}; + +Q_DECLARE_METATYPE(ldraw::Property) + +// Mapping of properties to types +#define LDFORGE_DEFINE_PROPERTY_TYPE(PROPERTY, TYPE) \ + namespace ldraw \ + { \ + template<> struct PropertyTraits<ldraw::Property::PROPERTY> \ + { \ + using type = TYPE; \ + static constexpr std::array<char, 256> name{#PROPERTY}; \ + static constexpr bool defined = true; \ + }; \ + } + +LDFORGE_DEFINE_PROPERTY_TYPE(Color, ldraw::Color) +LDFORGE_DEFINE_PROPERTY_TYPE(Text, QString) +LDFORGE_DEFINE_PROPERTY_TYPE(Point0, glm::vec3) +LDFORGE_DEFINE_PROPERTY_TYPE(Point1, glm::vec3) +LDFORGE_DEFINE_PROPERTY_TYPE(Point2, glm::vec3) +LDFORGE_DEFINE_PROPERTY_TYPE(Point3, glm::vec3) +LDFORGE_DEFINE_PROPERTY_TYPE(Transformation, glm::mat4) +LDFORGE_DEFINE_PROPERTY_TYPE(ReferenceName, QString) +LDFORGE_DEFINE_PROPERTY_TYPE(IsInverted, bool) +LDFORGE_DEFINE_PROPERTY_TYPE(ErrorMessage, QString) + +#define LDRAW_OBJECT_HANDLE_SET_PROPERTY(PROPERTY, HANDLER) \ + {this->handle<ldraw::Property::PROPERTY>(result, pair, \ + [&](const ldraw::PropertyType<ldraw::Property::PROPERTY>& value) HANDLER);} + +// Generics +namespace ldraw +{ + template<ldraw::Property property> + using PropertyType = typename PropertyTraits<property>::type; + + template<ldraw::Property property> + inline const char* PROPERTY_NAME = PropertyTraits<property>::name; + + struct PropertyKeyValue + { + Property key; + QVariant value; + }; + + constexpr Property pointProperty(int n) + { + Q_ASSERT(n >= 0 and n < 4); + return static_cast<Property>(static_cast<int>(Property::Point0) + n); + } + + struct PropertyTrait + { + ldraw::Property property; + std::array<char, 256> name; + int type; + }; + + namespace detail + { + template<int N> + constexpr int propertyCountHelper() + { + if constexpr (ldraw::PropertyTraits<static_cast<Property>(N)>::defined) + { + return propertyCountHelper<N + 1>(); + } + else + { + return N; + } + } + + template<int k> + constexpr PropertyTrait getPropertyTrait() + { + constexpr auto property = static_cast<ldraw::Property>(k); + using trait = ldraw::PropertyTraits<property>; + return PropertyTrait{ + property, + trait::name, + qMetaTypeId<typename trait::type>() + }; + } + + template<int... Ints> + auto getPropertyTraits(std::integer_sequence<int, Ints...>) + { + return std::array<PropertyTrait, sizeof...(Ints)>{getPropertyTrait<Ints>()...}; + } + } + + constexpr int NUM_PROPERTIES = detail::propertyCountHelper<0>(); + inline const auto& traits() + { + static std::array<PropertyTrait, NUM_PROPERTIES> result = + detail::getPropertyTraits(std::make_integer_sequence<int, NUM_PROPERTIES>()); + return result; + } + + inline const auto& traits(ldraw::Property property) + { + return traits()[static_cast<int>(property)]; + } + + template<typename T, std::size_t... Ints> + constexpr auto makeIndexArray(std::index_sequence<Ints...>) + { + return std::array{static_cast<T>(Ints)...}; + } + + constexpr auto ALL_PROPERTIES = makeIndexArray<Property>(std::make_index_sequence<NUM_PROPERTIES>{}); + + template<typename T> + bool testPropertyType(ldraw::Property property) + { + return qMetaTypeId<T>() == ldraw::traits(property).type; + } +}