Tue, 28 Sep 2021 23:07:23 +0300
Use QSaveFile to save the file more safely
#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; constexpr int MAX_POINTS = 4; struct PropertyKeyValue { Property key; QVariant value; }; constexpr Property pointProperty(int n) { Q_ASSERT(n >= 0 and n < MAX_POINTS); 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; } }