src/linetypes/propertygenerics.h

Tue, 28 Sep 2021 23:07:23 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 28 Sep 2021 23:07:23 +0300
changeset 145
4dea24d3eda0
parent 117
121a40d5e34c
child 186
922662adb72a
permissions
-rw-r--r--

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;
	}
}

mercurial